]> gerrit.simantics Code Review - simantics/fmil.git/blobdiff - org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java
Pending status can be returns from FMU to Native C to Java
[simantics/fmil.git] / org.simantics.fmil.core / src / org / simantics / fmil / core / FMIL.java
index 5c00607b9be349d4a03401a27397cb99cc97d9da..4b1eeaca132386d9e1071b4e6bac3569d25d8325 100644 (file)
-package org.simantics.fmil.core;\r
-\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.io.RandomAccessFile;\r
-import java.nio.channels.FileChannel;\r
-import java.nio.channels.FileLock;\r
-import java.util.ArrayList;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.osgi.framework.Bundle;\r
-import org.simantics.Simantics;\r
-import org.simantics.fmil.core.ExecEnvironment.ARCHType;\r
-import org.simantics.fmil.core.ExecEnvironment.OSType;\r
-import org.simantics.utils.FileUtils;\r
-\r
-import gnu.trove.list.array.TIntArrayList;\r
-import gnu.trove.map.hash.TObjectIntHashMap;\r
-\r
-\r
-public class FMIL {\r
-\r
-    /**\r
-     * Static variables\r
-     */\r
-    private static int      ERROR               = 0;\r
-    private static int      OK                  = 1;\r
-    private static String   UNSATISFIED_LINK    = "Method not found. DLL might not be loaded properly.";    \r
-    private static String   TEMP_FMU_DIRECTORY_NAME = "fmil";    \r
-    public static String    TEMP_FMU_COMMON_DIRECTORY;  \r
-    public static String    LOCK_FILE_NAME      = "fmil.lock";\r
-\r
-    public static Object syncObject = new Object();\r
-\r
-    /**\r
-     * Static: load native libraries required for the FMU simulation to work.\r
-     */\r
-    static {\r
-       \r
-        File[] libraries = new File[2];\r
-\r
-        Bundle bundle = null;\r
-        \r
-        ExecEnvironment env = ExecEnvironment.calculate();\r
-        if (env.os == OSType.WINDOWS) {\r
-            if (env.arch == ARCHType.X86) {\r
-                bundle = Platform.getBundle("org.simantics.fmil.win32");\r
-            } else if (env.arch == ARCHType.X86_64) {\r
-                bundle = Platform.getBundle("org.simantics.fmil.win64");\r
-            }\r
-        }\r
-        \r
-        if (bundle != null) {\r
-            try{\r
-                String root = FileLocator.getBundleFile(bundle).getAbsolutePath();\r
-//                if (env.arch == ARCHType.X86_64) {\r
-//                    File newFIle = new File(root, "libraries/libexpat.dll");\r
-//                    System.load(newFIle.getAbsolutePath());\r
-//                }\r
-//                libraries[0] = new File(root, "libraries/zlibwapi.dll");\r
-//                libraries[1] = new File(root, "libraries/miniunz.dll");\r
-                libraries[0] = new File(root, "libraries/fmilib_shared.dll");\r
-                libraries[1] = new File(root, "libraries/FMUSimulator.dll");\r
-            }\r
-            catch (Exception e) {\r
-                e.printStackTrace();\r
-            }\r
-        }\r
-\r
-        for(File library : libraries) {\r
-            if(library == null) {\r
-                System.err.println("FMU library not loaded. FMU simulation not working.");\r
-                continue;\r
-            } else if(!library.isFile()) {\r
-                System.err.println(library.getAbsolutePath() + " not found");\r
-            } else {\r
-                try {\r
-                    System.load(library.getAbsolutePath());\r
-                } catch (Throwable t) {\r
-                    System.err.println(t.getMessage());\r
-                }\r
-            } \r
-        }\r
-    }\r
-\r
-    /**\r
-     * Static: initialize fmu temp folder\r
-     */\r
-    static {\r
-        File dir = Simantics.getTemporaryDirectory(TEMP_FMU_DIRECTORY_NAME);\r
-        TEMP_FMU_COMMON_DIRECTORY = dir.getAbsolutePath(); \r
-    }\r
-\r
-\r
-    private String fmuDir;\r
-    private int id;\r
-\r
-    public String TEMP_FOLDER_1;\r
-    public String TEMP_FOLDER_2;\r
-    public String TEMP_FMU_DIRECTORY;\r
-    private String dirName;\r
-\r
-       private String[] variableNames;\r
-       private String[] variableDescriptions;\r
-       private String[] variableDeclaredTypes;\r
-       private int[] variableReferences;\r
-       private int[] variableTypes;\r
-       private int[] variableCausalities;\r
-       private int[] variableVariabilities;\r
-       \r
-       private String[] declaredTypes;\r
-       private String[] declaredTypeDescriptions;\r
-       private String[] declaredTypeQuantities;\r
-       private String[] declaredTypeUnits;\r
-       \r
-       private TObjectIntHashMap<String> variableMap = new TObjectIntHashMap<String>();\r
-       \r
-       private Set<String> subscriptionSet = new HashSet<String>();\r
-       private TIntArrayList subscription = new TIntArrayList();\r
-       private ArrayList<String> subscribedNames = new ArrayList<String>();\r
-       \r
-       public List<String> getSubscribedNames() {\r
-               return subscribedNames;\r
-       }\r
-       \r
-       public boolean subscribe(String name) throws FMILException {\r
-               // Safety check\r
-               int vr = variableMap.get(name);\r
-               if(vr == 0) return false;\r
-               if(!subscriptionSet.add(name)) return false;\r
-               subscribedNames.add(name);\r
-               System.err.println("subscribed : " + name + " => " + subscribedNames.size());\r
-               subscription.add(vr);\r
-               subscribe(new int[] { vr });\r
-               return true;\r
-       }\r
-\r
-    public FMIL() {\r
-        // Create a directory for this control\r
-        File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString());\r
-        tempDir.mkdir();\r
-        TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath();\r
-\r
-        // Create two directories inside the temp directory for this control\r
-        dirName = UUID.randomUUID().toString();\r
-        File fmuDir = new File(TEMP_FMU_DIRECTORY, dirName);\r
-        fmuDir.mkdir();\r
-\r
-        TEMP_FOLDER_1 = fmuDir.toString();\r
-        TEMP_FOLDER_2 = fmuDir.toString() + "_2";\r
-\r
-        // Lock fmu directory in temp directory\r
-        lockFMUDirectory();\r
-    }\r
-\r
-    public int getModelIDNew() {\r
-        return id;\r
-    }\r
-\r
-    public String getModelID() {\r
-        return dirName;\r
-    }\r
-\r
-    public String getFmuDir() {\r
-        return fmuDir;\r
-    }\r
-\r
-    /**\r
-     * Load fmu from a given file path. Releases the (possible) previously\r
-     * loaded fmu.\r
-     * \r
-     * @param path absolute file path for fmu file\r
-     * @throws FMILException\r
-     */\r
-    private int fmuN = 0;\r
-    private boolean fmuLoaded = false;\r
-    public void loadFMUFile(String path) throws FMILException {\r
-\r
-        synchronized(syncObject) {\r
-\r
-            if(fmuN % 2 == 0) {\r
-                fmuDir = TEMP_FOLDER_1;\r
-                fmuN++;\r
-            } else {\r
-                fmuDir = TEMP_FOLDER_2;\r
-                fmuN = 0;\r
-            }\r
-\r
-            File tempDir = new File(fmuDir);\r
-            if(tempDir.isDirectory()) {\r
-                try {\r
-                    FileUtils.deleteAll(tempDir);\r
-                } catch (IOException e) {\r
-                    throw new FMILException("Could not create temp folder for fmu");\r
-                }\r
-                tempDir.mkdir();\r
-            } else {\r
-                tempDir.mkdir();\r
-            }\r
-\r
-\r
-            try {\r
-                String tmpPath = tempDir.getAbsolutePath();\r
-                if(!tmpPath.endsWith("\\"))\r
-                    tmpPath = tmpPath + "\\";\r
-                id = loadFMUFile_(path, tmpPath);\r
-                \r
-                getAllVariables();\r
-                getAllVariableReferences();\r
-                \r
-                for(int i=0;i<variableNames.length;i++) {\r
-                       variableMap.put(variableNames[i], variableReferences[i]);\r
-                }\r
-\r
-                fmuLoaded = true;\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK, err);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int loadFMUFile_(String path, String toDir);\r
-\r
-    /**\r
-     * Set a step length for simulation\r
-     * \r
-     * @param step Step length for simulation\r
-     * @throws FMILException\r
-     */\r
-    public void setStepLength(double step) throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = setStepLength_(getModelIDNew(), step);\r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int setStepLength_(int id, double step);\r
-\r
-    /**\r
-     * Instantiates a simulation. \r
-     * <p>\r
-     * Make sure that an FMU is loaded first.\r
-     * @throws FMILException\r
-     */\r
-    public void instantiateSimulation() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = instantiateSimulation_(getModelIDNew()); \r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int instantiateSimulation_(int id);\r
-\r
-    \r
-    /**\r
-     * Initializes a simulation. \r
-     * <p>\r
-     * Make sure that simulation is instantiated first!\r
-     * @throws FMILException\r
-     */\r
-    public void initializeSimulation() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = initializeSimulation_(getModelIDNew()); \r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int initializeSimulation_(int id);\r
-\r
-    /**\r
-     * Subscribe a set of variables from a loaded simulation.\r
-     * <p>\r
-     * Make sure that an FMU is loaded first.\r
-     * @param variables Array of variables\r
-     * @throws FMILException\r
-     */\r
-    public void subscribe(int[] variables) throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = subscribe_(getModelIDNew(), variables); \r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int subscribe_(int id, int[] variables);\r
-\r
-    /**\r
-     * Set a new (Real, double) value for a variable. If the variable is a \r
-     * parameter, the change is effective immediately.\r
-     *  \r
-     * @param name Variable\r
-     * @param value New (Real, double) value\r
-     * @throws FMILException\r
-     */\r
-    public void setRealValue(String name, double value) throws FMILException {\r
-       \r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = setRealValue_(getModelIDNew(), variableMap.get(name), value); \r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-            \r
-        }\r
-        \r
-    }\r
-\r
-    public void setRealValue(int variableReference, double value) throws FMILException {\r
-       \r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = setRealValue_(getModelIDNew(), variableReference, value); \r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-            \r
-        }\r
-        \r
-    }\r
-\r
-    private native int setRealValue_(int id, int variableReference, double value);\r
-\r
-//    /**\r
-//     * Set a new (integer) value for a variable. If the variable is a \r
-//     * parameter, the change is effective immediately.\r
-//     *  \r
-//     * @param name Variable\r
-//     * @param value New (integer) value\r
-//     * @throws FMILException\r
-//     */\r
-//    public void setIntegerValue(String name, int value) throws FMILException {\r
-//        synchronized(syncObject) {\r
-//\r
-//            try {\r
-//\r
-//                int ret = setIntegerValue_(getModelID(), name, value); \r
-//                if(ret == ERROR)\r
-//                    throw new FMILException(getLastErrorMessage());\r
-//\r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//    private native int setIntegerValue_(String id, String name, int value);\r
-//\r
-//    /**\r
-//     * Set a new (boolean) value for a variable. If the variable is a \r
-//     * parameter, the change is effective immediately.\r
-//     *  \r
-//     * @param name Variable\r
-//     * @param value New (boolean) value\r
-//     * @throws FMILException\r
-//     */\r
-//    public void setBooleanValue(String name, boolean value) throws FMILException {\r
-//        synchronized(syncObject) {\r
-//\r
-//            try {\r
-//\r
-//                int ret = setBooleanValue_(getModelID(), name, value); \r
-//                if(ret == ERROR)\r
-//                    throw new FMILException(getLastErrorMessage());\r
-//\r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//    private native int setBooleanValue_(String id, String name, boolean value);\r
-//\r
-//    public void setTime(double time) throws FMILException {\r
-//        synchronized(syncObject) {\r
-//\r
-//            try {\r
-//\r
-//                int ret = setTime_(getModelID(), time); \r
-//                if(ret == ERROR)\r
-//                    throw new FMILException(getLastErrorMessage());\r
-//\r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//    private native int setTime_(String id, double time);\r
-\r
-    /**\r
-     * Simulate one step forward. The step length can be set with\r
-     * setStepLength()\r
-     * \r
-     * @throws FMILException\r
-     */\r
-    public void simulateStep() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                int ret = simulateStep_(getModelIDNew()); \r
-                if(ret == ERROR)\r
-                    throw new FMILException(getLastErrorMessage());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-    private native int simulateStep_(int id);\r
-\r
-    /**\r
-     * Get an array containing the current values for subscribed variables. The\r
-     * values are in the same order as in the subscription.\r
-     * \r
-     * @param results An array the size of subscribed results\r
-     * @return\r
-     */\r
-    public double[] getSubscribedResults() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               double[] results = new double[subscription.size()];\r
-                return getSubscribedResults_(getModelIDNew(), results);\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native double[] getSubscribedResults_(int id, double[] results);\r
-    \r
-\r
-    /**\r
-     * Unload FMU and the dll:s that it requires.\r
-     * <p>\r
-     * To be called after all FMU simulations are ended. \r
-     * If the fmu is loaded again / changed, call to loadFMUFile is sufficient. loadFMUFile \r
-     * releases the previous fmu.dll  \r
-     * \r
-     * @throws FMILException\r
-     */\r
-    public void unloadFMU() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                unlockFMUDirectory();\r
-                if(fmuLoaded) {\r
-                    int ret = unloadFMU_(getModelIDNew()); \r
-                    if(ret == ERROR)\r
-                        throw new FMILException(getLastErrorMessage());\r
-                }\r
-                removeFMUDirectoryContents();\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-    private native int unloadFMU_(int id);\r
-    \r
-//    /**\r
-//     * Checks if fmu has been initialized\r
-//     * @return current simulation time\r
-//     */\r
-//    public boolean isInitialized() throws FMILException {\r
-//        synchronized(syncObject) {\r
-//            try {\r
-//                return isInitialized_(getModelID());\r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//\r
-//    private native boolean isInitialized_(String id);\r
-//\r
-    /**\r
-     * Get the current simulation time\r
-     * @return current simulation time\r
-     */\r
-    public double getTime() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-                return getTime_(getModelIDNew());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native double getTime_(int id);\r
-\r
-    /**\r
-     * Get all variables in a loaded model\r
-     * @return all variables in a loaded model\r
-     */\r
-    public String[] getAllVariables() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableNames == null) {\r
-                       variableNames = getAllVariables_(getModelIDNew());\r
-               }\r
-               return variableNames;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllVariables_(int id);\r
-\r
-    public String[] getAllVariableDescriptions() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableDescriptions == null) {\r
-                       variableDescriptions = getAllVariableDescriptions_(getModelIDNew());\r
-               }\r
-               return variableDescriptions;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllVariableDescriptions_(int id);\r
-    \r
-    public String[] getAllVariableDeclaredTypes() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableDeclaredTypes == null) {\r
-                       variableDeclaredTypes = getAllVariableDeclaredTypes_(getModelIDNew());\r
-               }\r
-               return variableDeclaredTypes;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllVariableDeclaredTypes_(int id);\r
-\r
-    public int[] getAllVariableReferences() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableReferences == null) {\r
-                       variableReferences = getAllVariableReferences_(getModelIDNew(), new int[variableNames.length]); \r
-               }\r
-               return variableReferences;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int[] getAllVariableReferences_(int id, int[] array);\r
-\r
-    public int[] getAllVariableTypes() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableTypes == null) {\r
-                       variableTypes = getAllVariableTypes_(getModelIDNew(), new int[variableNames.length]); \r
-               }\r
-               return variableTypes;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int[] getAllVariableTypes_(int id, int[] array);\r
-\r
-    public int[] getAllVariableCausalities() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableCausalities == null) {\r
-                       variableCausalities = getAllVariableCausalities_(getModelIDNew(), new int[variableNames.length]); \r
-               }\r
-               return variableCausalities;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int[] getAllVariableCausalities_(int id, int[] array);\r
-\r
-    public int[] getAllVariableVariabilities() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(variableVariabilities == null) {\r
-                       variableVariabilities = getAllVariableVariabilities_(getModelIDNew(), new int[variableNames.length]); \r
-               }\r
-               return variableVariabilities;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native int[] getAllVariableVariabilities_(int id, int[] array);\r
-\r
-    /**\r
-     * Get all variables in a loaded model\r
-     * @return all variables in a loaded model\r
-     */\r
-    public String[] getAllDeclaredTypes() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(declaredTypes == null) {\r
-                       declaredTypes = getAllDeclaredTypes_(getModelIDNew());\r
-               }\r
-               return declaredTypes;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllDeclaredTypes_(int id);\r
-    \r
-    public String[] getAllDeclaredTypeDescriptions() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(declaredTypeDescriptions == null) {\r
-                       declaredTypeDescriptions = getAllDeclaredTypeDescriptions_(getModelIDNew());\r
-               }\r
-               return declaredTypeDescriptions;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllDeclaredTypeDescriptions_(int id);\r
-    \r
-    public String[] getAllDeclaredTypeQuantities() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(declaredTypeQuantities == null) {\r
-                       declaredTypeQuantities = getAllDeclaredTypeQuantities_(getModelIDNew());\r
-               }\r
-               return declaredTypeQuantities;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllDeclaredTypeQuantities_(int id);\r
-\r
-    public String[] getAllDeclaredTypeUnits() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               if(declaredTypeUnits == null) {\r
-                       declaredTypeUnits = getAllDeclaredTypeUnits_(getModelIDNew());\r
-               }\r
-               return declaredTypeUnits;\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native String[] getAllDeclaredTypeUnits_(int id);\r
-    \r
-    \r
-//\r
-//    /**\r
-//     * Get all variables from model that match the filter (and time variable)\r
-//     * \r
-//     * @param regexp Regular expression filter\r
-//     * @return An array of variable names that match regexp filter (and time-variable)\r
-//     * @throws FMILException\r
-//     */\r
-//    public String[] filterVariables(String regexp) throws FMILException {       \r
-//        synchronized(syncObject) {\r
-//            try {\r
-//\r
-//                return filterVariables_(getModelID(), regexp + "|time");\r
-//\r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//\r
-//    private native String[] filterVariables_(String id, String regexp);\r
-//\r
-    /**\r
-     * Get the last error message\r
-     * @return Last error message\r
-     */\r
-    public String getLastErrorMessage() throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-\r
-               return "err";\r
-                //return getLastErrorMessage_(getModelID());\r
-\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-//\r
-//    private native String getLastErrorMessage_(String id);\r
-\r
-    /**\r
-     * Get a real (double) value for variable\r
-     * @param name Name of the variable\r
-     * @return value\r
-     * @throws FMILException\r
-     */\r
-    public double getRealValue(String name) throws FMILException {\r
-        synchronized(syncObject) {\r
-\r
-            try {\r
-                // TODO: printtaa id ja name, jotta saadaan virheessä kiinni\r
-               double result = getRealValue_(getModelIDNew(), variableMap.get(name));\r
-               System.err.println("getRealValue " + name + " = " + result);\r
-                return  result;\r
-            } catch (UnsatisfiedLinkError err) {\r
-                throw new FMILException(UNSATISFIED_LINK);\r
-            } catch (Exception e) {\r
-                throw new FMILException(e.getMessage());\r
-            }\r
-        }\r
-    }\r
-\r
-    private native double getRealValue_(int id, int variableReference);\r
-\r
-//    /**\r
-//     * Get a string value for variable\r
-//     * @param name Name of the variable\r
-//     * @return value\r
-//     * @throws FMILException\r
-//     */\r
-//    public String getStringValue(String name) throws FMILException {\r
-//        synchronized(syncObject) {\r
-//\r
-//            try {\r
-//                return getStringValue_(getModelID(), name); \r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//\r
-//    private native String getStringValue_(String id, String name);\r
-//\r
-//    /**\r
-//     * Get an integer value for variable\r
-//     * @param name Name of the variable\r
-//     * @return value\r
-//     * @throws FMILException\r
-//     */\r
-//    public int getIntegerValue(String name) throws FMILException {\r
-//        synchronized(syncObject) {\r
-//\r
-//            try {\r
-//                return getIntegerValue_(getModelID(), name); \r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//\r
-//    private native int getIntegerValue_(String id, String name);\r
-//\r
-//    /**\r
-//     * Get a real (double) value for variable\r
-//     * @param name Name of the variable\r
-//     * @return value\r
-//     * @throws FMILException\r
-//     */\r
-//    public boolean getBooleanValue(String name) throws FMILException {\r
-//        synchronized(syncObject) {\r
-//\r
-//            try {\r
-//                return getBooleanValue_(getModelID(), name); \r
-//            } catch (UnsatisfiedLinkError err) {\r
-//                throw new FMILException(UNSATISFIED_LINK);\r
-//            } catch (Exception e) {\r
-//                throw new FMILException(e.getMessage());\r
-//            }\r
-//        }\r
-//    }\r
-//\r
-//    private native boolean getBooleanValue_(String id, String name);\r
-\r
-    private FileChannel channel; \r
-    private FileLock lock;\r
-\r
-    @SuppressWarnings("resource")\r
-    private boolean lockFMUDirectory() {\r
-\r
-        try {\r
-            // Get a file channel for the lock file\r
-            File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME);\r
-            if(!lockFile.isFile())\r
-                lockFile.createNewFile();\r
-\r
-            channel = new RandomAccessFile(lockFile, "rw").getChannel();\r
-\r
-            // Use the file channel to create a lock on the file.\r
-            // This method blocks until it can retrieve the lock.\r
-            lock = channel.lock();\r
-\r
-            //          // Try acquiring the lock without blocking. This method returns\r
-            //          // null or throws an exception if the file is already locked.\r
-            //          try {\r
-            //              lock = channel.tryLock();\r
-            //          } catch (OverlappingFileLockException e) {\r
-            //              // File is already locked in this thread or virtual machine\r
-            //          }\r
-        } catch (IOException e) {\r
-            return false;\r
-        }\r
-\r
-        return true;\r
-    }\r
-\r
-    private boolean unlockFMUDirectory() {\r
-        try {\r
-            // Release the lock\r
-            if(lock != null)\r
-                lock.release();\r
-\r
-            // Close the file\r
-            if(channel != null)\r
-                channel.close();\r
-        } catch (IOException e) {\r
-            return false;\r
-        }\r
-        return true;\r
-    }\r
-\r
-    private boolean removeFMUDirectoryContents() {\r
-        // Remove contents\r
-        try {\r
-            File tempDir = new File(TEMP_FMU_DIRECTORY);\r
-            FileUtils.deleteAll(tempDir);\r
-            tempDir.delete();\r
-        } catch (IOException e) {\r
-            return false;\r
-        }\r
-        return true;\r
-    }\r
-}\r
+package org.simantics.fmil.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+import org.simantics.fmil.core.ExecEnvironment.OSType;
+import org.simantics.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import gnu.trove.list.array.TIntArrayList;
+import gnu.trove.map.hash.TObjectIntHashMap;
+
+
+public class FMIL {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(FMIL.class);
+
+       private static final boolean DEBUG = false;
+    
+    /**
+     * Static variables
+     */
+    private static int      OK                  = 0;
+    private static int      ERROR               = 1;
+    private static int      PENDING                    = 2;
+    private static String   UNSATISFIED_LINK    = "Method not found. DLL might not be loaded properly.";
+    public static final String TEMP_FMU_DIRECTORY_NAME = "fmil";
+    public static String    TEMP_FMU_COMMON_DIRECTORY;
+    public static String    LOCK_FILE_NAME      = "fmil.lock";
+
+    public static Object syncObject = new Object();
+
+    /**
+     * Static: load native libraries required for the FMU simulation to work.
+     */
+    static {
+
+        File[] libraries = new File[2];
+
+        ExecEnvironment env = ExecEnvironment.calculate();
+
+        try {
+            URL sharedFMILIBUrl = null;
+            URL simulatorFMIUrl = null;
+            Bundle b = Platform.getBundle("org.simantics.fmil.core");
+
+            if (env.os == OSType.WINDOWS) {
+                sharedFMILIBUrl = FileLocator.find(b, new Path("libraries/fmilib_shared.dll"), null);
+                simulatorFMIUrl = FileLocator.find(b, new Path("libraries/FMUSimulator.dll"), null);
+            } else if(env.os == OSType.LINUX) {
+                sharedFMILIBUrl = FileLocator.find(b, new Path("libraries/libfmilib_shared.so"), null);
+                simulatorFMIUrl = FileLocator.find(b, new Path("libraries/libFMUSimulator.so"), null);
+            }
+
+            libraries[0] = new File(FileLocator.toFileURL(sharedFMILIBUrl).getPath());
+            libraries[1] = new File(FileLocator.toFileURL(simulatorFMIUrl).getPath());
+        } catch (Exception e) {
+            LOGGER.error("Failed to resolve native FMU simulation library for execution environment {}.{}", env.os, env.arch, e);
+        }
+
+        for(File library : libraries) {
+            if(library == null) {
+                System.err.println("FMU library not loaded. FMU simulation not working.");
+                continue;
+            } else if(!library.isFile()) {
+                System.err.println(library.getAbsolutePath() + " not found");
+            } else {
+                try {
+                    System.load(library.getAbsolutePath());
+                } catch (Throwable t) {
+                    System.err.println(t.getMessage());
+                }
+            } 
+        }
+    }
+
+    /**
+     * Static: initialize fmu temp folder from current working directory
+     */
+    static {
+        TEMP_FMU_COMMON_DIRECTORY = Paths.get(".").toAbsolutePath().normalize().toString();
+    }
+    
+    public static void setTempFMUCommonDir(File dir) {
+       TEMP_FMU_COMMON_DIRECTORY = dir.getAbsolutePath(); 
+    }
+
+    private String fmuDir;
+    private int id;
+
+    public String TEMP_FOLDER_1;
+    public String TEMP_FOLDER_2;
+    public String TEMP_FMU_DIRECTORY;
+    private String dirName;
+
+       private String[] variableNames;
+       private String[] variableDescriptions;
+       private String[] variableDeclaredTypes;
+       private int[] variableReferences;
+       private int[] variableTypes;
+       private int[] variableCausalities;
+       private int[] variableVariabilities;
+       
+       private String[] declaredTypes;
+       private String[] declaredTypeDescriptions;
+       private String[] declaredTypeQuantities;
+       private String[] declaredTypeUnits;
+       
+       private TObjectIntHashMap<String> variableMap = new TObjectIntHashMap<String>();
+       
+       private Set<String> subscriptionSet = new HashSet<String>();
+       private TIntArrayList subscription = new TIntArrayList();
+       private ArrayList<String> subscribedNames = new ArrayList<String>();
+       
+       public List<String> getSubscribedNames() {
+               return subscribedNames;
+       }
+       
+       public boolean subscribe(String name) throws FMILException {
+               synchronized(syncObject) {
+                       // Safety check
+                       int vr = variableMap.get(name);
+                       if(vr == 0) return false;
+                       if(!subscriptionSet.add(name)) return false;
+                       subscribedNames.add(name);
+                       subscription.add(vr);
+                       subscribe(new int[] { vr });
+                       return true;
+               }
+       }
+
+    public FMIL() {
+        // Create a directory for this control
+        File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString());
+        tempDir.mkdir();
+        TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath();
+
+        // Create two directories inside the temp directory for this control
+        dirName = UUID.randomUUID().toString();
+        File fmuDir = new File(TEMP_FMU_DIRECTORY, dirName);
+        fmuDir.mkdir();
+
+        TEMP_FOLDER_1 = fmuDir.toString();
+        TEMP_FOLDER_2 = fmuDir.toString() + "_2";
+
+        // Lock fmu directory in temp directory
+        lockFMUDirectory();
+    }
+
+    public int getModelIDNew() {
+        return id;
+    }
+
+    public String getModelID() {
+        return dirName;
+    }
+
+    public String getFmuDir() {
+        return fmuDir;
+    }
+
+    /**
+     * Load fmu from a given file path. Releases the (possible) previously
+     * loaded fmu.
+     * 
+     * @param path absolute file path for fmu file
+     * @throws FMILException
+     */
+    private int fmuN = 0;
+    private boolean fmuLoaded = false;
+    public void loadFMUFile(String path) throws FMILException {
+
+        if (!Files.exists(Paths.get(path)))
+            throw new FMILException("File " + path + " does not exist");
+        if (!Files.isRegularFile(Paths.get(path)))
+            throw new FMILException("Path " + path + " is not a file");
+
+        synchronized(syncObject) {
+
+            if(fmuN % 2 == 0) {
+                fmuDir = TEMP_FOLDER_1;
+                fmuN++;
+            } else {
+                fmuDir = TEMP_FOLDER_2;
+                fmuN = 0;
+            }
+
+            java.nio.file.Path tempDir = Paths.get(fmuDir);
+            if(Files.exists(tempDir) && Files.isDirectory(tempDir)) {
+                try {
+                       FileUtils.emptyDirectory(tempDir);
+                } catch (IOException e) {
+                    throw new FMILException("Could not delete existing files from temp folder for fmu " + path, e);
+                }
+            } else {
+                try {
+                       Files.createDirectory(tempDir);
+                } catch (IOException e) {
+                    throw new FMILException("Could not create temp folder for fmu " + path, e);
+                }
+            }
+
+            try {
+                String tmpPath = tempDir.toString();
+                if(!tmpPath.endsWith("\\") && !tmpPath.endsWith("/"))
+                    tmpPath = tmpPath + "/";
+                id = loadFMUFile_(path, tmpPath);
+                
+                getAllVariables();
+                getAllVariableReferences();
+                
+                for(int i=0;i<variableNames.length;i++) {
+                       variableMap.put(variableNames[i], variableReferences[i]);
+                }
+
+                fmuLoaded = true;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK, err);
+            } catch (Exception e) {
+               LOGGER.error(e.getMessage());
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int loadFMUFile_(String path, String toDir) throws FMILException;
+
+    /**
+     * Set a step length for simulation
+     * 
+     * @param step Step length for simulation
+     * @throws FMILException
+     */
+    public void setStepLength(double step) throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+                int ret = setStepLength_(getModelIDNew(), step);
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int setStepLength_(int id, double step);
+
+    /**
+     * Instantiates a simulation. 
+     * <p>
+     * Make sure that an FMU is loaded first.
+     * @throws FMILException
+     */
+    public void instantiateSimulation() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+                int ret = instantiateSimulation_(getModelIDNew()); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int instantiateSimulation_(int id) throws FMILException;
+
+    
+    /**
+     * Initializes a simulation. 
+     * <p>
+     * Make sure that simulation is instantiated first!
+     * @throws FMILException
+     */
+    public void initializeSimulation() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+                int ret = initializeSimulation_(getModelIDNew()); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int initializeSimulation_(int id) throws FMILException;
+
+    /**
+     * Subscribe a set of variables from a loaded simulation.
+     * <p>
+     * Make sure that an FMU is loaded first.
+     * @param variables Array of variables
+     * @throws FMILException
+     */
+    public void subscribe(int[] variables) throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+                int ret = subscribe_(getModelIDNew(), variables); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int subscribe_(int id, int[] variables);
+
+    /**
+     * Set value of a real variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setRealValue(String name, double value) throws FMILException {
+       setRealValue(variableMap.get(name), value);
+    }
+
+    /**
+     * Set value of a real variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setRealValue(int variableReference, double value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setRealValue_(getModelIDNew(), variableReference, value); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int setRealValue_(int id, int variableReference, double value) throws FMILException;
+
+    
+    /**
+     * Set value of an integer variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setIntegerValue(String name, int value) throws FMILException {
+       setIntegerValue(variableMap.get(name), value);
+    }
+
+    /**
+     * Set value of an integer variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setIntegerValue(int variableReference, int value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setIntegerValue_(getModelIDNew(), variableReference, value); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int setIntegerValue_(int id, int variableReference, int value) throws FMILException;
+
+    
+    /**
+     * Set value of a boolean variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setBooleanValue(String name, boolean value) throws FMILException {
+       setBooleanValue(variableMap.get(name), value);
+    }
+
+    /**
+     * Set value of a boolean variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setBooleanValue(int variableReference, boolean value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setBooleanValue_(getModelIDNew(), variableReference, value); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int setBooleanValue_(int id, int variableReference, boolean value) throws FMILException;
+
+    
+    /**
+     * Set value of a string variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable name
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setStringValue(String name, String value) throws FMILException {
+       setStringValue(variableMap.get(name), value);
+    }
+
+    /**
+     * Set value of a string variable. If the variable is a 
+     * parameter, the change is effective immediately.
+     *  
+     * @param name  Variable id
+     * @param value  New value
+     * @throws FMILException
+     */
+    public void setStringValue(int variableReference, String value) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                int ret = setStringValue_(getModelIDNew(), variableReference, value); 
+                if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int setStringValue_(int id, int variableReference, String value) throws FMILException;
+    
+
+    /**
+     * Simulate one step forward. The step length can be set with
+     * setStepLength()
+     * 
+     * @throws FMILException
+     */
+    public void simulateStep() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+                int ret = simulateStep_(getModelIDNew()); //0 is ok, 1 is error, 2 is pending
+                if(ret == PENDING)
+                    LOGGER.warn("Pending status return from FMU. This is not implemented in our Simulator yet!");
+                else if(ret != OK)
+                    LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    private native int simulateStep_(int id) throws FMILException;
+
+    /**
+     * Get an array containing the current values for subscribed variables. The
+     * values are in the same order as in the subscription.
+     * 
+     * @param results An array the size of subscribed results
+     * @return
+     */
+    public double[] getSubscribedResults() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+               
+               double[] results = new double[subscription.size()];
+               Arrays.fill(results, Double.NaN);
+               
+               return getSubscribedResults_(getModelIDNew(), results);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native double[] getSubscribedResults_(int id, double[] results);
+    
+
+    /**
+     * Unload FMU and the dll:s that it requires.
+     * <p>
+     * To be called after all FMU simulations are ended. 
+     * If the fmu is loaded again / changed, call to loadFMUFile is sufficient. loadFMUFile 
+     * releases the previous fmu.dll  
+     * 
+     * @throws FMILException
+     */
+    public void unloadFMU() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+                unlockFMUDirectory();
+                if(fmuLoaded) {
+                    int ret = unloadFMU_(getModelIDNew()); 
+                    if(ret != OK)
+                        LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
+                    fmuLoaded = false;
+                }
+                removeFMUDirectoryContents();
+
+            } catch (FMILException e) {
+                throw e;
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    private native int unloadFMU_(int id) throws FMILException;
+    
+//    /**
+//     * Checks if fmu has been initialized
+//     * @return current simulation time
+//     */
+//    public boolean isInitialized() throws FMILException {
+//        synchronized(syncObject) {
+//            try {
+//                return isInitialized_(getModelID());
+//            } catch (UnsatisfiedLinkError err) {
+//                throw new FMILException(UNSATISFIED_LINK);
+//            } catch (Exception e) {
+//                throw new FMILException(e.getMessage());
+//            }
+//        }
+//    }
+//
+//    private native boolean isInitialized_(String id);
+//
+    /**
+     * Get the current simulation time
+     * @return current simulation time
+     */
+    public double getTime() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+                return getTime_(getModelIDNew());
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native double getTime_(int id);
+
+    /**
+     * Get all variables in a loaded model
+     * @return all variables in a loaded model
+     */
+    public String[] getAllVariables() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableNames == null) {
+                       variableNames = getAllVariables_(getModelIDNew());
+               }
+               return variableNames;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllVariables_(int id);
+
+    public String[] getAllVariableDescriptions() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableDescriptions == null) {
+                       variableDescriptions = getAllVariableDescriptions_(getModelIDNew());
+               }
+               return variableDescriptions;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllVariableDescriptions_(int id);
+    
+    public String[] getAllVariableDeclaredTypes() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableDeclaredTypes == null) {
+                       variableDeclaredTypes = getAllVariableDeclaredTypes_(getModelIDNew());
+               }
+               return variableDeclaredTypes;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllVariableDeclaredTypes_(int id);
+
+    public int[] getAllVariableReferences() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableReferences == null) {
+                       variableReferences = getAllVariableReferences_(getModelIDNew(), new int[variableNames.length]); 
+               }
+               return variableReferences;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int[] getAllVariableReferences_(int id, int[] array);
+
+    public int[] getAllVariableTypes() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableTypes == null) {
+                       variableTypes = getAllVariableTypes_(getModelIDNew(), new int[variableNames.length]); 
+               }
+               return variableTypes;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int[] getAllVariableTypes_(int id, int[] array);
+
+    public int[] getAllVariableCausalities() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableCausalities == null) {
+                       variableCausalities = getAllVariableCausalities_(getModelIDNew(), new int[variableNames.length]); 
+               }
+               return variableCausalities;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int[] getAllVariableCausalities_(int id, int[] array);
+
+    public int[] getAllVariableVariabilities() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(variableVariabilities == null) {
+                       variableVariabilities = getAllVariableVariabilities_(getModelIDNew(), new int[variableNames.length]); 
+               }
+               return variableVariabilities;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native int[] getAllVariableVariabilities_(int id, int[] array);
+
+    /**
+     * Get all variables in a loaded model
+     * @return all variables in a loaded model
+     */
+    public String[] getAllDeclaredTypes() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(declaredTypes == null) {
+                       declaredTypes = getAllDeclaredTypes_(getModelIDNew());
+               }
+               return declaredTypes;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllDeclaredTypes_(int id);
+    
+    public String[] getAllDeclaredTypeDescriptions() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(declaredTypeDescriptions == null) {
+                       declaredTypeDescriptions = getAllDeclaredTypeDescriptions_(getModelIDNew());
+               }
+               return declaredTypeDescriptions;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllDeclaredTypeDescriptions_(int id);
+    
+    public String[] getAllDeclaredTypeQuantities() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(declaredTypeQuantities == null) {
+                       declaredTypeQuantities = getAllDeclaredTypeQuantities_(getModelIDNew());
+               }
+               return declaredTypeQuantities;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllDeclaredTypeQuantities_(int id);
+
+    public String[] getAllDeclaredTypeUnits() throws FMILException {
+        synchronized(syncObject) {
+
+            try {
+
+               if(declaredTypeUnits == null) {
+                       declaredTypeUnits = getAllDeclaredTypeUnits_(getModelIDNew());
+               }
+               return declaredTypeUnits;
+
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+
+    private native String[] getAllDeclaredTypeUnits_(int id);
+    
+    
+//
+//    /**
+//     * Get all variables from model that match the filter (and time variable)
+//     * 
+//     * @param regexp Regular expression filter
+//     * @return An array of variable names that match regexp filter (and time-variable)
+//     * @throws FMILException
+//     */
+//    public String[] filterVariables(String regexp) throws FMILException {       
+//        synchronized(syncObject) {
+//            try {
+//
+//                return filterVariables_(getModelID(), regexp + "|time");
+//
+//            } catch (UnsatisfiedLinkError err) {
+//                throw new FMILException(UNSATISFIED_LINK);
+//            } catch (Exception e) {
+//                throw new FMILException(e.getMessage());
+//            }
+//        }
+//    }
+//
+//    private native String[] filterVariables_(String id, String regexp);
+////
+//    /**
+//     * Get the last error message
+//     * @return Last error message
+//     */
+//    public String getLastErrorMessage() throws FMILException {
+//        synchronized(syncObject) {
+//
+//            try {
+//
+//             return "err";
+//                //return getLastErrorMessage_(getModelID());
+//
+//            } catch (UnsatisfiedLinkError err) {
+//                throw new FMILException(UNSATISFIED_LINK);
+//            } catch (Exception e) {
+//                throw new FMILException(e.getMessage());
+//            }
+//        }
+//    }
+//
+//    private native String getLastErrorMessage_(String id);
+
+    /**
+     * Get a value (double) for real variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public double getRealValue(String name) throws FMILException {
+       double result = getRealValue(variableMap.get(name)); 
+       if (DEBUG) System.err.println("getRealValue " + name + " = " + result);
+       return result;
+    }
+
+    /**
+     * Get a value (double) for real variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public double getRealValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                return getRealValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native double getRealValue_(int id, int variableReference) throws FMILException;
+
+
+    /**
+     * Get value of integer variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public int getIntegerValue(String name) throws FMILException {
+       int result = getIntegerValue(variableMap.get(name));
+       if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
+       return result;
+    }
+
+    /**
+     * Get a real (double) value for variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public int getIntegerValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                return getIntegerValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native int getIntegerValue_(int id, int variableReference) throws FMILException;
+    
+    
+    /**
+     * Get value of boolean variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public boolean getBooleanValue(String name) throws FMILException {
+       boolean result = getBooleanValue(variableMap.get(name));
+       if (DEBUG) System.err.println("getBooleanValue " + name + " = " + result);
+       return result;
+    }
+
+    /**
+     * Get value of boolean variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public boolean getBooleanValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                return getBooleanValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native boolean getBooleanValue_(int id, int variableReference) throws FMILException;
+    
+    
+    /**
+     * Get value of string variable
+     * @param name Name of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public String getStringValue(String name) throws FMILException {
+       String result = getStringValue(variableMap.get(name));
+       if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
+       return result;
+    }
+
+    /**
+     * Get value of string variable
+     * @param variableReference  Numeric id of the variable
+     * @return value
+     * @throws FMILException
+     */
+    public String getStringValue(int variableReference) throws FMILException {
+        synchronized(syncObject) {
+            try {
+                return getStringValue_(getModelIDNew(), variableReference);
+            } catch (UnsatisfiedLinkError err) {
+                throw new FMILException(UNSATISFIED_LINK);
+            } catch (Exception e) {
+                throw new FMILException(e.getMessage());
+            }
+        }
+    }
+    
+    private native String getStringValue_(int id, int variableReference) throws FMILException;
+    
+
+    private FileChannel channel; 
+    private FileLock lock;
+
+    @SuppressWarnings("resource")
+    private boolean lockFMUDirectory() {
+
+        try {
+            // Get a file channel for the lock file
+            File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME);
+            if(!lockFile.isFile())
+                lockFile.createNewFile();
+
+            channel = new RandomAccessFile(lockFile, "rw").getChannel();
+
+            // Use the file channel to create a lock on the file.
+            // This method blocks until it can retrieve the lock.
+            lock = channel.lock();
+
+            //          // Try acquiring the lock without blocking. This method returns
+            //          // null or throws an exception if the file is already locked.
+            //          try {
+            //              lock = channel.tryLock();
+            //          } catch (OverlappingFileLockException e) {
+            //              // File is already locked in this thread or virtual machine
+            //          }
+        } catch (IOException e) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean unlockFMUDirectory() {
+        try {
+            // Release the lock
+            if(lock != null)
+                lock.release();
+
+            // Close the file
+            if(channel != null)
+                channel.close();
+        } catch (IOException e) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean removeFMUDirectoryContents() {
+        // Remove contents
+        try {
+            File tempDir = new File(TEMP_FMU_DIRECTORY);
+            FileUtils.deleteAll(tempDir);
+            tempDir.delete();
+        } catch (IOException e) {
+            return false;
+        }
+        return true;
+    }
+    
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            unloadFMU();
+        } catch (Throwable t) {
+            LOGGER.error("Could not unload native FMU!", t);
+        } finally {
+            super.finalize();
+        }
+    }
+}