]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/src/org/simantics/fmil/core/FMIL.java
Variable with index 0 cannot be handled by FMIL
[simantics/fmil.git] / org.simantics.fmil.core / src / org / simantics / fmil / core / FMIL.java
1 package org.simantics.fmil.core;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.RandomAccessFile;
6 import java.net.URL;
7 import java.nio.channels.FileChannel;
8 import java.nio.channels.FileLock;
9 import java.nio.file.Files;
10 import java.nio.file.Paths;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16 import java.util.UUID;
17
18 import org.eclipse.core.runtime.FileLocator;
19 import org.eclipse.core.runtime.Path;
20 import org.eclipse.core.runtime.Platform;
21 import org.osgi.framework.Bundle;
22 import org.simantics.fmil.core.ExecEnvironment.OSType;
23 import org.simantics.utils.FileUtils;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import gnu.trove.list.array.TIntArrayList;
28 import gnu.trove.map.hash.TObjectIntHashMap;
29
30
31 public class FMIL {
32
33     private static final Logger LOGGER = LoggerFactory.getLogger(FMIL.class);
34
35         private static final boolean DEBUG = false;
36     
37     /**
38      * Static variables
39      */
40     private static int      OK                  = 0;
41     private static int      ERROR               = 1;
42     private static int      PENDING                     = 2;
43     private static String   UNSATISFIED_LINK    = "Method not found. DLL might not be loaded properly.";
44     public static final String TEMP_FMU_DIRECTORY_NAME = "fmil";
45     public static String    TEMP_FMU_COMMON_DIRECTORY;
46     public static String    LOCK_FILE_NAME      = "fmil.lock";
47
48     public static Object syncObject = new Object();
49
50     /**
51      * Static: load native libraries required for the FMU simulation to work.
52      */
53     static {
54
55         File[] libraries = new File[2];
56
57         ExecEnvironment env = ExecEnvironment.calculate();
58
59         try {
60             URL sharedFMILIBUrl = null;
61             URL simulatorFMIUrl = null;
62             Bundle b = Platform.getBundle("org.simantics.fmil.core");
63
64             if (env.os == OSType.WINDOWS) {
65                 sharedFMILIBUrl = FileLocator.find(b, new Path("libraries/fmilib_shared.dll"), null);
66                 simulatorFMIUrl = FileLocator.find(b, new Path("libraries/FMUSimulator.dll"), null);
67             } else if(env.os == OSType.LINUX) {
68                 sharedFMILIBUrl = FileLocator.find(b, new Path("libraries/libfmilib_shared.so"), null);
69                 simulatorFMIUrl = FileLocator.find(b, new Path("libraries/libFMUSimulator.so"), null);
70             }
71
72             libraries[0] = new File(FileLocator.toFileURL(sharedFMILIBUrl).getPath());
73             libraries[1] = new File(FileLocator.toFileURL(simulatorFMIUrl).getPath());
74         } catch (Exception e) {
75             LOGGER.error("Failed to resolve native FMU simulation library for execution environment {}.{}", env.os, env.arch, e);
76         }
77
78         for(File library : libraries) {
79             if(library == null) {
80                 System.err.println("FMU library not loaded. FMU simulation not working.");
81                 continue;
82             } else if(!library.isFile()) {
83                 System.err.println(library.getAbsolutePath() + " not found");
84             } else {
85                 try {
86                     System.load(library.getAbsolutePath());
87                 } catch (Throwable t) {
88                     System.err.println(t.getMessage());
89                 }
90             } 
91         }
92     }
93
94     /**
95      * Static: initialize fmu temp folder from current working directory
96      */
97     static {
98         TEMP_FMU_COMMON_DIRECTORY = Paths.get(".").toAbsolutePath().normalize().toString();
99     }
100     
101     public static void setTempFMUCommonDir(File dir) {
102         TEMP_FMU_COMMON_DIRECTORY = dir.getAbsolutePath(); 
103     }
104
105     private String fmuDir;
106     private int id;
107
108     public String TEMP_FOLDER_1;
109     public String TEMP_FOLDER_2;
110     public String TEMP_FMU_DIRECTORY;
111     private String dirName;
112
113         private String[] variableNames;
114         private String[] variableDescriptions;
115         private String[] variableDeclaredTypes;
116         private int[] variableReferences;
117         private int[] variableTypes;
118         private int[] variableCausalities;
119         private int[] variableVariabilities;
120         
121         private String[] declaredTypes;
122         private String[] declaredTypeDescriptions;
123         private String[] declaredTypeQuantities;
124         private String[] declaredTypeUnits;
125         
126         private static int NO_VARIABLE_KEY = -1;
127         
128         private TObjectIntHashMap<String> variableMap = new TObjectIntHashMap<String>(10, 0.5f, NO_VARIABLE_KEY);
129         
130         private Set<String> subscriptionSet = new HashSet<String>();
131         private TIntArrayList subscription = new TIntArrayList();
132         private ArrayList<String> subscribedNames = new ArrayList<String>();
133         
134         public List<String> getSubscribedNames() {
135                 return subscribedNames;
136         }
137         
138         public boolean subscribe(String name) throws FMILException {
139                 synchronized(syncObject) {
140                         // Safety check
141                         int vr = variableMap.get(name);
142                         if(vr == NO_VARIABLE_KEY) return false;
143                         if(!subscriptionSet.add(name)) return false;
144                         subscribedNames.add(name);
145                         subscription.add(vr);
146                         subscribe(new int[] { vr });
147                         return true;
148                 }
149         }
150
151     public FMIL() {
152         // Create a directory for this control
153         File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString());
154         tempDir.mkdir();
155         TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath();
156
157         // Create two directories inside the temp directory for this control
158         dirName = UUID.randomUUID().toString();
159         File fmuDir = new File(TEMP_FMU_DIRECTORY, dirName);
160         fmuDir.mkdir();
161
162         TEMP_FOLDER_1 = fmuDir.toString();
163         TEMP_FOLDER_2 = fmuDir.toString() + "_2";
164
165         // Lock fmu directory in temp directory
166         lockFMUDirectory();
167     }
168
169     public int getModelIDNew() {
170         return id;
171     }
172
173     public String getModelID() {
174         return dirName;
175     }
176
177     public String getFmuDir() {
178         return fmuDir;
179     }
180
181     /**
182      * Load fmu from a given file path. Releases the (possible) previously
183      * loaded fmu.
184      * 
185      * @param path absolute file path for fmu file
186      * @throws FMILException
187      */
188     private int fmuN = 0;
189     private boolean instantiated = false;
190     public void loadFMUFile(String path) throws FMILException {
191
192         if (!Files.exists(Paths.get(path)))
193             throw new FMILException("File " + path + " does not exist");
194         if (!Files.isRegularFile(Paths.get(path)))
195             throw new FMILException("Path " + path + " is not a file");
196
197         synchronized(syncObject) {
198
199             if(fmuN % 2 == 0) {
200                 fmuDir = TEMP_FOLDER_1;
201                 fmuN++;
202             } else {
203                 fmuDir = TEMP_FOLDER_2;
204                 fmuN = 0;
205             }
206
207             java.nio.file.Path tempDir = Paths.get(fmuDir);
208             if(Files.exists(tempDir) && Files.isDirectory(tempDir)) {
209                 try {
210                         FileUtils.emptyDirectory(tempDir);
211                 } catch (IOException e) {
212                     throw new FMILException("Could not delete existing files from temp folder for fmu " + path, e);
213                 }
214             } else {
215                 try {
216                         Files.createDirectory(tempDir);
217                 } catch (IOException e) {
218                     throw new FMILException("Could not create temp folder for fmu " + path, e);
219                 }
220             }
221
222             try {
223                 String tmpPath = tempDir.toString();
224                 if(!tmpPath.endsWith("\\") && !tmpPath.endsWith("/"))
225                     tmpPath = tmpPath + "/";
226                 id = loadFMUFile_(path, tmpPath);
227                 
228                 getAllVariables();
229                 getAllVariableReferences();
230                 
231                 for(int i=0;i<variableNames.length;i++) {
232                         variableMap.put(variableNames[i], variableReferences[i]);
233                 }
234                 
235                 instantiated = false;
236             } catch (UnsatisfiedLinkError err) {
237                 throw new FMILException(UNSATISFIED_LINK, err);
238             } catch (Exception e) {
239                 LOGGER.error(e.getMessage());
240                 throw new FMILException(e.getMessage());
241             }
242         }
243     }
244
245     private native int loadFMUFile_(String path, String toDir) throws FMILException;
246
247     /**
248      * Set a step length for simulation
249      * 
250      * @param step Step length for simulation
251      * @throws FMILException
252      */
253     public void setStepLength(double step) throws FMILException {
254         synchronized(syncObject) {
255
256             try {
257                 int ret = setStepLength_(getModelIDNew(), step);
258                 if(ret != OK)
259                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
260
261             } catch (UnsatisfiedLinkError err) {
262                 throw new FMILException(UNSATISFIED_LINK);
263             } catch (Exception e) {
264                 throw new FMILException(e.getMessage());
265             }
266         }
267     }
268
269     private native int setStepLength_(int id, double step);
270
271     /**
272      * Instantiates a simulation. 
273      * <p>
274      * Make sure that an FMU is loaded first.
275      * @throws FMILException
276      */
277     public void instantiateSimulation() throws FMILException {
278         synchronized(syncObject) {
279
280             try {
281
282                 int ret = instantiateSimulation_(getModelIDNew()); 
283                 if(ret != OK) {
284                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
285                 } else {
286                         instantiated = true;
287                 }
288             } catch (FMILException e) {
289                 throw e;
290             } catch (UnsatisfiedLinkError err) {
291                 throw new FMILException(UNSATISFIED_LINK);
292             } catch (Exception e) {
293                 throw new FMILException(e.getMessage());
294             }
295         }
296     }
297
298     private native int instantiateSimulation_(int id) throws FMILException;
299
300     
301     /**
302      * Initializes a simulation. 
303      * <p>
304      * Make sure that simulation is instantiated first!
305      * @throws FMILException
306      */
307     public void initializeSimulation() throws FMILException {
308         synchronized(syncObject) {
309
310             try {
311
312                 int ret = initializeSimulation_(getModelIDNew()); 
313                 if(ret != OK)
314                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
315
316             } catch (FMILException e) {
317                 throw e;
318             } catch (UnsatisfiedLinkError err) {
319                 throw new FMILException(UNSATISFIED_LINK);
320             } catch (Exception e) {
321                 throw new FMILException(e.getMessage());
322             }
323         }
324     }
325
326     private native int initializeSimulation_(int id) throws FMILException;
327
328     /**
329      * Subscribe a set of variables from a loaded simulation.
330      * <p>
331      * Make sure that an FMU is loaded first.
332      * @param variables Array of variables
333      * @throws FMILException
334      */
335     public void subscribe(int[] variables) throws FMILException {
336         synchronized(syncObject) {
337
338             try {
339
340                 int ret = subscribe_(getModelIDNew(), variables); 
341                 if(ret != OK)
342                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
343
344             } catch (UnsatisfiedLinkError err) {
345                 throw new FMILException(UNSATISFIED_LINK);
346             } catch (Exception e) {
347                 throw new FMILException(e.getMessage());
348             }
349         }
350     }
351
352     private native int subscribe_(int id, int[] variables);
353
354     /**
355      * Set value of a real variable. If the variable is a 
356      * parameter, the change is effective immediately.
357      *  
358      * @param name  Variable name
359      * @param value  New value
360      * @throws FMILException
361      */
362     public void setRealValue(String name, double value) throws FMILException {
363         int key = variableMap.get(name);
364         if(key == NO_VARIABLE_KEY)
365                 throw new FMILException("No variable with name " + name);
366         setRealValue(key, value);
367     }
368
369     /**
370      * Set value of a real variable. If the variable is a 
371      * parameter, the change is effective immediately.
372      *  
373      * @param name  Variable id
374      * @param value  New value
375      * @throws FMILException
376      */
377     public void setRealValue(int variableReference, double value) throws FMILException {
378         synchronized(syncObject) {
379             try {
380                 int ret = setRealValue_(getModelIDNew(), variableReference, value); 
381                 if(ret != OK)
382                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
383             } catch (FMILException e) {
384                 throw e;
385             } catch (UnsatisfiedLinkError err) {
386                 throw new FMILException(UNSATISFIED_LINK);
387             } catch (Exception e) {
388                 throw new FMILException(e.getMessage());
389             }
390         }
391     }
392
393     private native int setRealValue_(int id, int variableReference, double value) throws FMILException;
394
395     
396     /**
397      * Set value of an integer variable. If the variable is a 
398      * parameter, the change is effective immediately.
399      *  
400      * @param name  Variable name
401      * @param value  New value
402      * @throws FMILException
403      */
404     public void setIntegerValue(String name, int value) throws FMILException {
405         int key = variableMap.get(name);
406         if(key == NO_VARIABLE_KEY)
407                 throw new FMILException("No variable with name " + name);
408         setIntegerValue(key, value);
409     }
410
411     /**
412      * Set value of an integer variable. If the variable is a 
413      * parameter, the change is effective immediately.
414      *  
415      * @param name  Variable id
416      * @param value  New value
417      * @throws FMILException
418      */
419     public void setIntegerValue(int variableReference, int value) throws FMILException {
420         synchronized(syncObject) {
421             try {
422                 int ret = setIntegerValue_(getModelIDNew(), variableReference, value); 
423                 if(ret != OK)
424                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
425             } catch (FMILException e) {
426                 throw e;
427             } catch (UnsatisfiedLinkError err) {
428                 throw new FMILException(UNSATISFIED_LINK);
429             } catch (Exception e) {
430                 throw new FMILException(e.getMessage());
431             }
432         }
433     }
434
435     private native int setIntegerValue_(int id, int variableReference, int value) throws FMILException;
436
437     
438     /**
439      * Set value of a boolean variable. If the variable is a 
440      * parameter, the change is effective immediately.
441      *  
442      * @param name  Variable name
443      * @param value  New value
444      * @throws FMILException
445      */
446     public void setBooleanValue(String name, boolean value) throws FMILException {
447         int key = variableMap.get(name);
448         if(key == NO_VARIABLE_KEY)
449                 throw new FMILException("No variable with name " + name);
450         setBooleanValue(key, value);
451     }
452
453     /**
454      * Set value of a boolean variable. If the variable is a 
455      * parameter, the change is effective immediately.
456      *  
457      * @param name  Variable id
458      * @param value  New value
459      * @throws FMILException
460      */
461     public void setBooleanValue(int variableReference, boolean value) throws FMILException {
462         synchronized(syncObject) {
463             try {
464                 int ret = setBooleanValue_(getModelIDNew(), variableReference, value); 
465                 if(ret != OK)
466                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
467             } catch (FMILException e) {
468                 throw e;
469             } catch (UnsatisfiedLinkError err) {
470                 throw new FMILException(UNSATISFIED_LINK);
471             } catch (Exception e) {
472                 throw new FMILException(e.getMessage());
473             }
474         }
475     }
476
477     private native int setBooleanValue_(int id, int variableReference, boolean value) throws FMILException;
478
479     
480     /**
481      * Set value of a string variable. If the variable is a 
482      * parameter, the change is effective immediately.
483      *  
484      * @param name  Variable name
485      * @param value  New value
486      * @throws FMILException
487      */
488     public void setStringValue(String name, String value) throws FMILException {
489         int key = variableMap.get(name);
490         if(key == NO_VARIABLE_KEY)
491                 throw new FMILException("No variable with name " + name);
492         setStringValue(key, value);
493     }
494
495     /**
496      * Set value of a string variable. If the variable is a 
497      * parameter, the change is effective immediately.
498      *  
499      * @param name  Variable id
500      * @param value  New value
501      * @throws FMILException
502      */
503     public void setStringValue(int variableReference, String value) throws FMILException {
504         synchronized(syncObject) {
505             try {
506                 int ret = setStringValue_(getModelIDNew(), variableReference, value); 
507                 if(ret != OK)
508                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
509             } catch (FMILException e) {
510                 throw e;
511             } catch (UnsatisfiedLinkError err) {
512                 throw new FMILException(UNSATISFIED_LINK);
513             } catch (Exception e) {
514                 throw new FMILException(e.getMessage());
515             }
516         }
517     }
518
519     private native int setStringValue_(int id, int variableReference, String value) throws FMILException;
520     
521
522     /**
523      * Simulate one step forward. The step length can be set with
524      * setStepLength()
525      * 
526      * @throws FMILException
527      */
528     public void simulateStep() throws FMILException {
529         synchronized(syncObject) {
530
531             try {
532
533                 int ret = simulateStep_(getModelIDNew()); //0 is ok, 1 is error, 2 is pending
534                 if(ret == PENDING)
535                     LOGGER.warn("Pending status return from FMU. This is not implemented in our Simulator yet!");
536                 else if(ret != OK)
537                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
538             } catch (FMILException e) {
539                 throw e;
540             } catch (UnsatisfiedLinkError err) {
541                 throw new FMILException(UNSATISFIED_LINK);
542             } catch (Exception e) {
543                 throw new FMILException(e.getMessage());
544             }
545         }
546     }
547     private native int simulateStep_(int id) throws FMILException;
548
549     /**
550      * Get an array containing the current values for subscribed variables. The
551      * values are in the same order as in the subscription.
552      * 
553      * @param results An array the size of subscribed results
554      * @return
555      */
556     public double[] getSubscribedResults() throws FMILException {
557         synchronized(syncObject) {
558
559             try {
560                 
561                 double[] results = new double[subscription.size()];
562                 Arrays.fill(results, Double.NaN);
563                 
564                 return getSubscribedResults_(getModelIDNew(), results);
565             } catch (UnsatisfiedLinkError err) {
566                 throw new FMILException(UNSATISFIED_LINK);
567             } catch (Exception e) {
568                 throw new FMILException(e.getMessage());
569             }
570         }
571     }
572
573     private native double[] getSubscribedResults_(int id, double[] results);
574     
575
576     /**
577      * Unload FMU and the dll:s that it requires.
578      * <p>
579      * To be called after all FMU simulations are ended. 
580      * If the fmu is loaded again / changed, call to loadFMUFile is sufficient. loadFMUFile 
581      * releases the previous fmu.dll  
582      * 
583      * @throws FMILException
584      */
585     public void unloadFMU() throws FMILException {
586         synchronized(syncObject) {
587
588             try {
589
590                 unlockFMUDirectory();
591                 
592                 // Many FMUs will not correctly clean-up during unload if the simulation isn't instantiated
593                 // Essentially we'd likely be passing an invalid pointer to the FMU to cleanup, causing native c-level crashes.
594                 
595                 if(instantiated) {
596                     int ret = unloadFMU_(getModelIDNew()); 
597                     if(ret != OK)
598                         LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
599                     instantiated = false;
600                 }
601                 removeFMUDirectoryContents();
602
603             } catch (FMILException e) {
604                 throw e;
605             } catch (UnsatisfiedLinkError err) {
606                 throw new FMILException(UNSATISFIED_LINK);
607             } catch (Exception e) {
608                 throw new FMILException(e.getMessage());
609             }
610         }
611     }
612     private native int unloadFMU_(int id) throws FMILException;
613     
614 //    /**
615 //     * Checks if fmu has been initialized
616 //     * @return current simulation time
617 //     */
618 //    public boolean isInitialized() throws FMILException {
619 //        synchronized(syncObject) {
620 //            try {
621 //                return isInitialized_(getModelID());
622 //            } catch (UnsatisfiedLinkError err) {
623 //                throw new FMILException(UNSATISFIED_LINK);
624 //            } catch (Exception e) {
625 //                throw new FMILException(e.getMessage());
626 //            }
627 //        }
628 //    }
629 //
630 //    private native boolean isInitialized_(String id);
631 //
632     /**
633      * Get the current simulation time
634      * @return current simulation time
635      */
636     public double getTime() throws FMILException {
637         synchronized(syncObject) {
638
639             try {
640
641                 return getTime_(getModelIDNew());
642
643             } catch (UnsatisfiedLinkError err) {
644                 throw new FMILException(UNSATISFIED_LINK);
645             } catch (Exception e) {
646                 throw new FMILException(e.getMessage());
647             }
648         }
649     }
650
651     private native double getTime_(int id);
652
653     /**
654      * Get all variables in a loaded model
655      * @return all variables in a loaded model
656      */
657     public String[] getAllVariables() throws FMILException {
658         synchronized(syncObject) {
659
660             try {
661
662                 if(variableNames == null) {
663                         variableNames = getAllVariables_(getModelIDNew());
664                 }
665                 return variableNames;
666
667             } catch (UnsatisfiedLinkError err) {
668                 throw new FMILException(UNSATISFIED_LINK);
669             } catch (Exception e) {
670                 throw new FMILException(e.getMessage());
671             }
672         }
673     }
674
675     private native String[] getAllVariables_(int id);
676
677     public String[] getAllVariableDescriptions() throws FMILException {
678         synchronized(syncObject) {
679
680             try {
681
682                 if(variableDescriptions == null) {
683                         variableDescriptions = getAllVariableDescriptions_(getModelIDNew());
684                 }
685                 return variableDescriptions;
686
687             } catch (UnsatisfiedLinkError err) {
688                 throw new FMILException(UNSATISFIED_LINK);
689             } catch (Exception e) {
690                 throw new FMILException(e.getMessage());
691             }
692         }
693     }
694
695     private native String[] getAllVariableDescriptions_(int id);
696     
697     public String[] getAllVariableDeclaredTypes() throws FMILException {
698         synchronized(syncObject) {
699
700             try {
701
702                 if(variableDeclaredTypes == null) {
703                         variableDeclaredTypes = getAllVariableDeclaredTypes_(getModelIDNew());
704                 }
705                 return variableDeclaredTypes;
706
707             } catch (UnsatisfiedLinkError err) {
708                 throw new FMILException(UNSATISFIED_LINK);
709             } catch (Exception e) {
710                 throw new FMILException(e.getMessage());
711             }
712         }
713     }
714
715     private native String[] getAllVariableDeclaredTypes_(int id);
716
717     public int[] getAllVariableReferences() throws FMILException {
718         synchronized(syncObject) {
719
720             try {
721
722                 if(variableReferences == null) {
723                         variableReferences = getAllVariableReferences_(getModelIDNew(), new int[variableNames.length]); 
724                 }
725                 return variableReferences;
726
727             } catch (UnsatisfiedLinkError err) {
728                 throw new FMILException(UNSATISFIED_LINK);
729             } catch (Exception e) {
730                 throw new FMILException(e.getMessage());
731             }
732         }
733     }
734
735     private native int[] getAllVariableReferences_(int id, int[] array);
736
737     public int[] getAllVariableTypes() throws FMILException {
738         synchronized(syncObject) {
739
740             try {
741
742                 if(variableTypes == null) {
743                         variableTypes = getAllVariableTypes_(getModelIDNew(), new int[variableNames.length]); 
744                 }
745                 return variableTypes;
746
747             } catch (UnsatisfiedLinkError err) {
748                 throw new FMILException(UNSATISFIED_LINK);
749             } catch (Exception e) {
750                 throw new FMILException(e.getMessage());
751             }
752         }
753     }
754
755     private native int[] getAllVariableTypes_(int id, int[] array);
756
757     public int[] getAllVariableCausalities() throws FMILException {
758         synchronized(syncObject) {
759
760             try {
761
762                 if(variableCausalities == null) {
763                         variableCausalities = getAllVariableCausalities_(getModelIDNew(), new int[variableNames.length]); 
764                 }
765                 return variableCausalities;
766
767             } catch (UnsatisfiedLinkError err) {
768                 throw new FMILException(UNSATISFIED_LINK);
769             } catch (Exception e) {
770                 throw new FMILException(e.getMessage());
771             }
772         }
773     }
774
775     private native int[] getAllVariableCausalities_(int id, int[] array);
776
777     public int[] getAllVariableVariabilities() throws FMILException {
778         synchronized(syncObject) {
779
780             try {
781
782                 if(variableVariabilities == null) {
783                         variableVariabilities = getAllVariableVariabilities_(getModelIDNew(), new int[variableNames.length]); 
784                 }
785                 return variableVariabilities;
786
787             } catch (UnsatisfiedLinkError err) {
788                 throw new FMILException(UNSATISFIED_LINK);
789             } catch (Exception e) {
790                 throw new FMILException(e.getMessage());
791             }
792         }
793     }
794
795     private native int[] getAllVariableVariabilities_(int id, int[] array);
796
797     /**
798      * Get all variables in a loaded model
799      * @return all variables in a loaded model
800      */
801     public String[] getAllDeclaredTypes() throws FMILException {
802         synchronized(syncObject) {
803
804             try {
805
806                 if(declaredTypes == null) {
807                         declaredTypes = getAllDeclaredTypes_(getModelIDNew());
808                 }
809                 return declaredTypes;
810
811             } catch (UnsatisfiedLinkError err) {
812                 throw new FMILException(UNSATISFIED_LINK);
813             } catch (Exception e) {
814                 throw new FMILException(e.getMessage());
815             }
816         }
817     }
818
819     private native String[] getAllDeclaredTypes_(int id);
820     
821     public String[] getAllDeclaredTypeDescriptions() throws FMILException {
822         synchronized(syncObject) {
823
824             try {
825
826                 if(declaredTypeDescriptions == null) {
827                         declaredTypeDescriptions = getAllDeclaredTypeDescriptions_(getModelIDNew());
828                 }
829                 return declaredTypeDescriptions;
830
831             } catch (UnsatisfiedLinkError err) {
832                 throw new FMILException(UNSATISFIED_LINK);
833             } catch (Exception e) {
834                 throw new FMILException(e.getMessage());
835             }
836         }
837     }
838
839     private native String[] getAllDeclaredTypeDescriptions_(int id);
840     
841     public String[] getAllDeclaredTypeQuantities() throws FMILException {
842         synchronized(syncObject) {
843
844             try {
845
846                 if(declaredTypeQuantities == null) {
847                         declaredTypeQuantities = getAllDeclaredTypeQuantities_(getModelIDNew());
848                 }
849                 return declaredTypeQuantities;
850
851             } catch (UnsatisfiedLinkError err) {
852                 throw new FMILException(UNSATISFIED_LINK);
853             } catch (Exception e) {
854                 throw new FMILException(e.getMessage());
855             }
856         }
857     }
858
859     private native String[] getAllDeclaredTypeQuantities_(int id);
860
861     public String[] getAllDeclaredTypeUnits() throws FMILException {
862         synchronized(syncObject) {
863
864             try {
865
866                 if(declaredTypeUnits == null) {
867                         declaredTypeUnits = getAllDeclaredTypeUnits_(getModelIDNew());
868                 }
869                 return declaredTypeUnits;
870
871             } catch (UnsatisfiedLinkError err) {
872                 throw new FMILException(UNSATISFIED_LINK);
873             } catch (Exception e) {
874                 throw new FMILException(e.getMessage());
875             }
876         }
877     }
878
879     private native String[] getAllDeclaredTypeUnits_(int id);
880     
881     
882 //
883 //    /**
884 //     * Get all variables from model that match the filter (and time variable)
885 //     * 
886 //     * @param regexp Regular expression filter
887 //     * @return An array of variable names that match regexp filter (and time-variable)
888 //     * @throws FMILException
889 //     */
890 //    public String[] filterVariables(String regexp) throws FMILException {       
891 //        synchronized(syncObject) {
892 //            try {
893 //
894 //                return filterVariables_(getModelID(), regexp + "|time");
895 //
896 //            } catch (UnsatisfiedLinkError err) {
897 //                throw new FMILException(UNSATISFIED_LINK);
898 //            } catch (Exception e) {
899 //                throw new FMILException(e.getMessage());
900 //            }
901 //        }
902 //    }
903 //
904 //    private native String[] filterVariables_(String id, String regexp);
905 ////
906 //    /**
907 //     * Get the last error message
908 //     * @return Last error message
909 //     */
910 //    public String getLastErrorMessage() throws FMILException {
911 //        synchronized(syncObject) {
912 //
913 //            try {
914 //
915 //              return "err";
916 //                //return getLastErrorMessage_(getModelID());
917 //
918 //            } catch (UnsatisfiedLinkError err) {
919 //                throw new FMILException(UNSATISFIED_LINK);
920 //            } catch (Exception e) {
921 //                throw new FMILException(e.getMessage());
922 //            }
923 //        }
924 //    }
925 //
926 //    private native String getLastErrorMessage_(String id);
927
928     /**
929      * Get a value (double) for real variable
930      * @param name Name of the variable
931      * @return value
932      * @throws FMILException
933      */
934     public double getRealValue(String name) throws FMILException {
935         int key = variableMap.get(name);
936         if(key == NO_VARIABLE_KEY)
937                 throw new FMILException("No variable with name " + name);
938         double result = getRealValue(key); 
939         if (DEBUG) System.err.println("getRealValue " + name + " = " + result);
940         return result;
941     }
942
943     /**
944      * Get a value (double) for real variable
945      * @param variableReference  Numeric id of the variable
946      * @return value
947      * @throws FMILException
948      */
949     public double getRealValue(int variableReference) throws FMILException {
950         synchronized(syncObject) {
951             try {
952                 return getRealValue_(getModelIDNew(), variableReference);
953             } catch (UnsatisfiedLinkError err) {
954                 throw new FMILException(UNSATISFIED_LINK);
955             } catch (Exception e) {
956                 throw new FMILException(e.getMessage());
957             }
958         }
959     }
960     
961     private native double getRealValue_(int id, int variableReference) throws FMILException;
962
963
964     /**
965      * Get value of integer variable
966      * @param name Name of the variable
967      * @return value
968      * @throws FMILException
969      */
970     public int getIntegerValue(String name) throws FMILException {
971         int key = variableMap.get(name);
972         if(key == NO_VARIABLE_KEY)
973                 throw new FMILException("No variable with name " + name);
974         int result = getIntegerValue(key);
975         if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
976         return result;
977     }
978
979     /**
980      * Get a real (double) value for variable
981      * @param variableReference  Numeric id of the variable
982      * @return value
983      * @throws FMILException
984      */
985     public int getIntegerValue(int variableReference) throws FMILException {
986         synchronized(syncObject) {
987             try {
988                 return getIntegerValue_(getModelIDNew(), variableReference);
989             } catch (UnsatisfiedLinkError err) {
990                 throw new FMILException(UNSATISFIED_LINK);
991             } catch (Exception e) {
992                 throw new FMILException(e.getMessage());
993             }
994         }
995     }
996     
997     private native int getIntegerValue_(int id, int variableReference) throws FMILException;
998     
999     
1000     /**
1001      * Get value of boolean variable
1002      * @param name Name of the variable
1003      * @return value
1004      * @throws FMILException
1005      */
1006     public boolean getBooleanValue(String name) throws FMILException {
1007         int key = variableMap.get(name);
1008         if(key == NO_VARIABLE_KEY)
1009                 throw new FMILException("No variable with name " + name);
1010         boolean result = getBooleanValue(key);
1011         if (DEBUG) System.err.println("getBooleanValue " + name + " = " + result);
1012         return result;
1013     }
1014
1015     /**
1016      * Get value of boolean variable
1017      * @param variableReference  Numeric id of the variable
1018      * @return value
1019      * @throws FMILException
1020      */
1021     public boolean getBooleanValue(int variableReference) throws FMILException {
1022         synchronized(syncObject) {
1023             try {
1024                 return getBooleanValue_(getModelIDNew(), variableReference);
1025             } catch (UnsatisfiedLinkError err) {
1026                 throw new FMILException(UNSATISFIED_LINK);
1027             } catch (Exception e) {
1028                 throw new FMILException(e.getMessage());
1029             }
1030         }
1031     }
1032     
1033     private native boolean getBooleanValue_(int id, int variableReference) throws FMILException;
1034     
1035     
1036     /**
1037      * Get value of string variable
1038      * @param name Name of the variable
1039      * @return value
1040      * @throws FMILException
1041      */
1042     public String getStringValue(String name) throws FMILException {
1043         int key = variableMap.get(name);
1044         if(key == NO_VARIABLE_KEY)
1045                 throw new FMILException("No variable with name " + name);
1046         String result = getStringValue(key);
1047         if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
1048         return result;
1049     }
1050
1051     /**
1052      * Get value of string variable
1053      * @param variableReference  Numeric id of the variable
1054      * @return value
1055      * @throws FMILException
1056      */
1057     public String getStringValue(int variableReference) throws FMILException {
1058         synchronized(syncObject) {
1059             try {
1060                 return getStringValue_(getModelIDNew(), variableReference);
1061             } catch (UnsatisfiedLinkError err) {
1062                 throw new FMILException(UNSATISFIED_LINK);
1063             } catch (Exception e) {
1064                 throw new FMILException(e.getMessage());
1065             }
1066         }
1067     }
1068     
1069     private native String getStringValue_(int id, int variableReference) throws FMILException;
1070     
1071
1072     private FileChannel channel; 
1073     private FileLock lock;
1074
1075     @SuppressWarnings("resource")
1076     private boolean lockFMUDirectory() {
1077
1078         try {
1079             // Get a file channel for the lock file
1080             File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME);
1081             if(!lockFile.isFile())
1082                 lockFile.createNewFile();
1083
1084             channel = new RandomAccessFile(lockFile, "rw").getChannel();
1085
1086             // Use the file channel to create a lock on the file.
1087             // This method blocks until it can retrieve the lock.
1088             lock = channel.lock();
1089
1090             //          // Try acquiring the lock without blocking. This method returns
1091             //          // null or throws an exception if the file is already locked.
1092             //          try {
1093             //              lock = channel.tryLock();
1094             //          } catch (OverlappingFileLockException e) {
1095             //              // File is already locked in this thread or virtual machine
1096             //          }
1097         } catch (IOException e) {
1098             return false;
1099         }
1100
1101         return true;
1102     }
1103
1104     private boolean unlockFMUDirectory() {
1105         try {
1106             // Release the lock
1107             if(lock != null)
1108                 lock.release();
1109
1110             // Close the file
1111             if(channel != null)
1112                 channel.close();
1113         } catch (IOException e) {
1114             return false;
1115         }
1116         return true;
1117     }
1118
1119     private boolean removeFMUDirectoryContents() {
1120         // Remove contents
1121         try {
1122             File tempDir = new File(TEMP_FMU_DIRECTORY);
1123             FileUtils.deleteAll(tempDir);
1124             tempDir.delete();
1125         } catch (IOException e) {
1126             return false;
1127         }
1128         return true;
1129     }
1130     
1131     @Override
1132     protected void finalize() throws Throwable {
1133         try {
1134             unloadFMU();
1135         } catch (Throwable t) {
1136             LOGGER.error("Could not unload native FMU!", t);
1137         } finally {
1138             super.finalize();
1139         }
1140     }
1141 }