]> gerrit.simantics Code Review - simantics/fmil.git/blob - 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
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 TObjectIntHashMap<String> variableMap = new TObjectIntHashMap<String>();
127         
128         private Set<String> subscriptionSet = new HashSet<String>();
129         private TIntArrayList subscription = new TIntArrayList();
130         private ArrayList<String> subscribedNames = new ArrayList<String>();
131         
132         public List<String> getSubscribedNames() {
133                 return subscribedNames;
134         }
135         
136         public boolean subscribe(String name) throws FMILException {
137                 synchronized(syncObject) {
138                         // Safety check
139                         int vr = variableMap.get(name);
140                         if(vr == 0) return false;
141                         if(!subscriptionSet.add(name)) return false;
142                         subscribedNames.add(name);
143                         subscription.add(vr);
144                         subscribe(new int[] { vr });
145                         return true;
146                 }
147         }
148
149     public FMIL() {
150         // Create a directory for this control
151         File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString());
152         tempDir.mkdir();
153         TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath();
154
155         // Create two directories inside the temp directory for this control
156         dirName = UUID.randomUUID().toString();
157         File fmuDir = new File(TEMP_FMU_DIRECTORY, dirName);
158         fmuDir.mkdir();
159
160         TEMP_FOLDER_1 = fmuDir.toString();
161         TEMP_FOLDER_2 = fmuDir.toString() + "_2";
162
163         // Lock fmu directory in temp directory
164         lockFMUDirectory();
165     }
166
167     public int getModelIDNew() {
168         return id;
169     }
170
171     public String getModelID() {
172         return dirName;
173     }
174
175     public String getFmuDir() {
176         return fmuDir;
177     }
178
179     /**
180      * Load fmu from a given file path. Releases the (possible) previously
181      * loaded fmu.
182      * 
183      * @param path absolute file path for fmu file
184      * @throws FMILException
185      */
186     private int fmuN = 0;
187     private boolean fmuLoaded = false;
188     public void loadFMUFile(String path) throws FMILException {
189
190         if (!Files.exists(Paths.get(path)))
191             throw new FMILException("File " + path + " does not exist");
192         if (!Files.isRegularFile(Paths.get(path)))
193             throw new FMILException("Path " + path + " is not a file");
194
195         synchronized(syncObject) {
196
197             if(fmuN % 2 == 0) {
198                 fmuDir = TEMP_FOLDER_1;
199                 fmuN++;
200             } else {
201                 fmuDir = TEMP_FOLDER_2;
202                 fmuN = 0;
203             }
204
205             java.nio.file.Path tempDir = Paths.get(fmuDir);
206             if(Files.exists(tempDir) && Files.isDirectory(tempDir)) {
207                 try {
208                         FileUtils.emptyDirectory(tempDir);
209                 } catch (IOException e) {
210                     throw new FMILException("Could not delete existing files from temp folder for fmu " + path, e);
211                 }
212             } else {
213                 try {
214                         Files.createDirectory(tempDir);
215                 } catch (IOException e) {
216                     throw new FMILException("Could not create temp folder for fmu " + path, e);
217                 }
218             }
219
220             try {
221                 String tmpPath = tempDir.toString();
222                 if(!tmpPath.endsWith("\\") && !tmpPath.endsWith("/"))
223                     tmpPath = tmpPath + "/";
224                 id = loadFMUFile_(path, tmpPath);
225                 
226                 getAllVariables();
227                 getAllVariableReferences();
228                 
229                 for(int i=0;i<variableNames.length;i++) {
230                         variableMap.put(variableNames[i], variableReferences[i]);
231                 }
232
233                 fmuLoaded = true;
234             } catch (UnsatisfiedLinkError err) {
235                 throw new FMILException(UNSATISFIED_LINK, err);
236             } catch (Exception e) {
237                 LOGGER.error(e.getMessage());
238                 throw new FMILException(e.getMessage());
239             }
240         }
241     }
242
243     private native int loadFMUFile_(String path, String toDir) throws FMILException;
244
245     /**
246      * Set a step length for simulation
247      * 
248      * @param step Step length for simulation
249      * @throws FMILException
250      */
251     public void setStepLength(double step) throws FMILException {
252         synchronized(syncObject) {
253
254             try {
255                 int ret = setStepLength_(getModelIDNew(), step);
256                 if(ret != OK)
257                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
258
259             } catch (UnsatisfiedLinkError err) {
260                 throw new FMILException(UNSATISFIED_LINK);
261             } catch (Exception e) {
262                 throw new FMILException(e.getMessage());
263             }
264         }
265     }
266
267     private native int setStepLength_(int id, double step);
268
269     /**
270      * Instantiates a simulation. 
271      * <p>
272      * Make sure that an FMU is loaded first.
273      * @throws FMILException
274      */
275     public void instantiateSimulation() throws FMILException {
276         synchronized(syncObject) {
277
278             try {
279
280                 int ret = instantiateSimulation_(getModelIDNew()); 
281                 if(ret != OK)
282                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
283
284             } catch (FMILException e) {
285                 throw e;
286             } catch (UnsatisfiedLinkError err) {
287                 throw new FMILException(UNSATISFIED_LINK);
288             } catch (Exception e) {
289                 throw new FMILException(e.getMessage());
290             }
291         }
292     }
293
294     private native int instantiateSimulation_(int id) throws FMILException;
295
296     
297     /**
298      * Initializes a simulation. 
299      * <p>
300      * Make sure that simulation is instantiated first!
301      * @throws FMILException
302      */
303     public void initializeSimulation() throws FMILException {
304         synchronized(syncObject) {
305
306             try {
307
308                 int ret = initializeSimulation_(getModelIDNew()); 
309                 if(ret != OK)
310                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
311
312             } catch (FMILException e) {
313                 throw e;
314             } catch (UnsatisfiedLinkError err) {
315                 throw new FMILException(UNSATISFIED_LINK);
316             } catch (Exception e) {
317                 throw new FMILException(e.getMessage());
318             }
319         }
320     }
321
322     private native int initializeSimulation_(int id) throws FMILException;
323
324     /**
325      * Subscribe a set of variables from a loaded simulation.
326      * <p>
327      * Make sure that an FMU is loaded first.
328      * @param variables Array of variables
329      * @throws FMILException
330      */
331     public void subscribe(int[] variables) throws FMILException {
332         synchronized(syncObject) {
333
334             try {
335
336                 int ret = subscribe_(getModelIDNew(), variables); 
337                 if(ret != OK)
338                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
339
340             } catch (UnsatisfiedLinkError err) {
341                 throw new FMILException(UNSATISFIED_LINK);
342             } catch (Exception e) {
343                 throw new FMILException(e.getMessage());
344             }
345         }
346     }
347
348     private native int subscribe_(int id, int[] variables);
349
350     /**
351      * Set value of a real variable. If the variable is a 
352      * parameter, the change is effective immediately.
353      *  
354      * @param name  Variable name
355      * @param value  New value
356      * @throws FMILException
357      */
358     public void setRealValue(String name, double value) throws FMILException {
359         setRealValue(variableMap.get(name), value);
360     }
361
362     /**
363      * Set value of a real variable. If the variable is a 
364      * parameter, the change is effective immediately.
365      *  
366      * @param name  Variable id
367      * @param value  New value
368      * @throws FMILException
369      */
370     public void setRealValue(int variableReference, double value) throws FMILException {
371         synchronized(syncObject) {
372             try {
373                 int ret = setRealValue_(getModelIDNew(), variableReference, value); 
374                 if(ret != OK)
375                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
376             } catch (FMILException e) {
377                 throw e;
378             } catch (UnsatisfiedLinkError err) {
379                 throw new FMILException(UNSATISFIED_LINK);
380             } catch (Exception e) {
381                 throw new FMILException(e.getMessage());
382             }
383         }
384     }
385
386     private native int setRealValue_(int id, int variableReference, double value) throws FMILException;
387
388     
389     /**
390      * Set value of an integer variable. If the variable is a 
391      * parameter, the change is effective immediately.
392      *  
393      * @param name  Variable name
394      * @param value  New value
395      * @throws FMILException
396      */
397     public void setIntegerValue(String name, int value) throws FMILException {
398         setIntegerValue(variableMap.get(name), value);
399     }
400
401     /**
402      * Set value of an integer variable. If the variable is a 
403      * parameter, the change is effective immediately.
404      *  
405      * @param name  Variable id
406      * @param value  New value
407      * @throws FMILException
408      */
409     public void setIntegerValue(int variableReference, int value) throws FMILException {
410         synchronized(syncObject) {
411             try {
412                 int ret = setIntegerValue_(getModelIDNew(), variableReference, value); 
413                 if(ret != OK)
414                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
415             } catch (FMILException e) {
416                 throw e;
417             } catch (UnsatisfiedLinkError err) {
418                 throw new FMILException(UNSATISFIED_LINK);
419             } catch (Exception e) {
420                 throw new FMILException(e.getMessage());
421             }
422         }
423     }
424
425     private native int setIntegerValue_(int id, int variableReference, int value) throws FMILException;
426
427     
428     /**
429      * Set value of a boolean variable. If the variable is a 
430      * parameter, the change is effective immediately.
431      *  
432      * @param name  Variable name
433      * @param value  New value
434      * @throws FMILException
435      */
436     public void setBooleanValue(String name, boolean value) throws FMILException {
437         setBooleanValue(variableMap.get(name), value);
438     }
439
440     /**
441      * Set value of a boolean variable. If the variable is a 
442      * parameter, the change is effective immediately.
443      *  
444      * @param name  Variable id
445      * @param value  New value
446      * @throws FMILException
447      */
448     public void setBooleanValue(int variableReference, boolean value) throws FMILException {
449         synchronized(syncObject) {
450             try {
451                 int ret = setBooleanValue_(getModelIDNew(), variableReference, value); 
452                 if(ret != OK)
453                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
454             } catch (FMILException e) {
455                 throw e;
456             } catch (UnsatisfiedLinkError err) {
457                 throw new FMILException(UNSATISFIED_LINK);
458             } catch (Exception e) {
459                 throw new FMILException(e.getMessage());
460             }
461         }
462     }
463
464     private native int setBooleanValue_(int id, int variableReference, boolean value) throws FMILException;
465
466     
467     /**
468      * Set value of a string variable. If the variable is a 
469      * parameter, the change is effective immediately.
470      *  
471      * @param name  Variable name
472      * @param value  New value
473      * @throws FMILException
474      */
475     public void setStringValue(String name, String value) throws FMILException {
476         setStringValue(variableMap.get(name), value);
477     }
478
479     /**
480      * Set value of a string variable. If the variable is a 
481      * parameter, the change is effective immediately.
482      *  
483      * @param name  Variable id
484      * @param value  New value
485      * @throws FMILException
486      */
487     public void setStringValue(int variableReference, String value) throws FMILException {
488         synchronized(syncObject) {
489             try {
490                 int ret = setStringValue_(getModelIDNew(), variableReference, value); 
491                 if(ret != OK)
492                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
493             } catch (FMILException e) {
494                 throw e;
495             } catch (UnsatisfiedLinkError err) {
496                 throw new FMILException(UNSATISFIED_LINK);
497             } catch (Exception e) {
498                 throw new FMILException(e.getMessage());
499             }
500         }
501     }
502
503     private native int setStringValue_(int id, int variableReference, String value) throws FMILException;
504     
505
506     /**
507      * Simulate one step forward. The step length can be set with
508      * setStepLength()
509      * 
510      * @throws FMILException
511      */
512     public void simulateStep() throws FMILException {
513         synchronized(syncObject) {
514
515             try {
516
517                 int ret = simulateStep_(getModelIDNew()); //0 is ok, 1 is error, 2 is pending
518                 if(ret == PENDING)
519                     LOGGER.warn("Pending status return from FMU. This is not implemented in our Simulator yet!");
520                 else if(ret != OK)
521                     LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
522             } catch (FMILException e) {
523                 throw e;
524             } catch (UnsatisfiedLinkError err) {
525                 throw new FMILException(UNSATISFIED_LINK);
526             } catch (Exception e) {
527                 throw new FMILException(e.getMessage());
528             }
529         }
530     }
531     private native int simulateStep_(int id) throws FMILException;
532
533     /**
534      * Get an array containing the current values for subscribed variables. The
535      * values are in the same order as in the subscription.
536      * 
537      * @param results An array the size of subscribed results
538      * @return
539      */
540     public double[] getSubscribedResults() throws FMILException {
541         synchronized(syncObject) {
542
543             try {
544                 
545                 double[] results = new double[subscription.size()];
546                 Arrays.fill(results, Double.NaN);
547                 
548                 return getSubscribedResults_(getModelIDNew(), results);
549             } catch (UnsatisfiedLinkError err) {
550                 throw new FMILException(UNSATISFIED_LINK);
551             } catch (Exception e) {
552                 throw new FMILException(e.getMessage());
553             }
554         }
555     }
556
557     private native double[] getSubscribedResults_(int id, double[] results);
558     
559
560     /**
561      * Unload FMU and the dll:s that it requires.
562      * <p>
563      * To be called after all FMU simulations are ended. 
564      * If the fmu is loaded again / changed, call to loadFMUFile is sufficient. loadFMUFile 
565      * releases the previous fmu.dll  
566      * 
567      * @throws FMILException
568      */
569     public void unloadFMU() throws FMILException {
570         synchronized(syncObject) {
571
572             try {
573
574                 unlockFMUDirectory();
575                 if(fmuLoaded) {
576                     int ret = unloadFMU_(getModelIDNew()); 
577                     if(ret != OK)
578                         LOGGER.warn("Function return value != OK, an exception should have been thrown from native code!");
579                     fmuLoaded = false;
580                 }
581                 removeFMUDirectoryContents();
582
583             } catch (FMILException e) {
584                 throw e;
585             } catch (UnsatisfiedLinkError err) {
586                 throw new FMILException(UNSATISFIED_LINK);
587             } catch (Exception e) {
588                 throw new FMILException(e.getMessage());
589             }
590         }
591     }
592     private native int unloadFMU_(int id) throws FMILException;
593     
594 //    /**
595 //     * Checks if fmu has been initialized
596 //     * @return current simulation time
597 //     */
598 //    public boolean isInitialized() throws FMILException {
599 //        synchronized(syncObject) {
600 //            try {
601 //                return isInitialized_(getModelID());
602 //            } catch (UnsatisfiedLinkError err) {
603 //                throw new FMILException(UNSATISFIED_LINK);
604 //            } catch (Exception e) {
605 //                throw new FMILException(e.getMessage());
606 //            }
607 //        }
608 //    }
609 //
610 //    private native boolean isInitialized_(String id);
611 //
612     /**
613      * Get the current simulation time
614      * @return current simulation time
615      */
616     public double getTime() throws FMILException {
617         synchronized(syncObject) {
618
619             try {
620
621                 return getTime_(getModelIDNew());
622
623             } catch (UnsatisfiedLinkError err) {
624                 throw new FMILException(UNSATISFIED_LINK);
625             } catch (Exception e) {
626                 throw new FMILException(e.getMessage());
627             }
628         }
629     }
630
631     private native double getTime_(int id);
632
633     /**
634      * Get all variables in a loaded model
635      * @return all variables in a loaded model
636      */
637     public String[] getAllVariables() throws FMILException {
638         synchronized(syncObject) {
639
640             try {
641
642                 if(variableNames == null) {
643                         variableNames = getAllVariables_(getModelIDNew());
644                 }
645                 return variableNames;
646
647             } catch (UnsatisfiedLinkError err) {
648                 throw new FMILException(UNSATISFIED_LINK);
649             } catch (Exception e) {
650                 throw new FMILException(e.getMessage());
651             }
652         }
653     }
654
655     private native String[] getAllVariables_(int id);
656
657     public String[] getAllVariableDescriptions() throws FMILException {
658         synchronized(syncObject) {
659
660             try {
661
662                 if(variableDescriptions == null) {
663                         variableDescriptions = getAllVariableDescriptions_(getModelIDNew());
664                 }
665                 return variableDescriptions;
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[] getAllVariableDescriptions_(int id);
676     
677     public String[] getAllVariableDeclaredTypes() throws FMILException {
678         synchronized(syncObject) {
679
680             try {
681
682                 if(variableDeclaredTypes == null) {
683                         variableDeclaredTypes = getAllVariableDeclaredTypes_(getModelIDNew());
684                 }
685                 return variableDeclaredTypes;
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[] getAllVariableDeclaredTypes_(int id);
696
697     public int[] getAllVariableReferences() throws FMILException {
698         synchronized(syncObject) {
699
700             try {
701
702                 if(variableReferences == null) {
703                         variableReferences = getAllVariableReferences_(getModelIDNew(), new int[variableNames.length]); 
704                 }
705                 return variableReferences;
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 int[] getAllVariableReferences_(int id, int[] array);
716
717     public int[] getAllVariableTypes() throws FMILException {
718         synchronized(syncObject) {
719
720             try {
721
722                 if(variableTypes == null) {
723                         variableTypes = getAllVariableTypes_(getModelIDNew(), new int[variableNames.length]); 
724                 }
725                 return variableTypes;
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[] getAllVariableTypes_(int id, int[] array);
736
737     public int[] getAllVariableCausalities() throws FMILException {
738         synchronized(syncObject) {
739
740             try {
741
742                 if(variableCausalities == null) {
743                         variableCausalities = getAllVariableCausalities_(getModelIDNew(), new int[variableNames.length]); 
744                 }
745                 return variableCausalities;
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[] getAllVariableCausalities_(int id, int[] array);
756
757     public int[] getAllVariableVariabilities() throws FMILException {
758         synchronized(syncObject) {
759
760             try {
761
762                 if(variableVariabilities == null) {
763                         variableVariabilities = getAllVariableVariabilities_(getModelIDNew(), new int[variableNames.length]); 
764                 }
765                 return variableVariabilities;
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[] getAllVariableVariabilities_(int id, int[] array);
776
777     /**
778      * Get all variables in a loaded model
779      * @return all variables in a loaded model
780      */
781     public String[] getAllDeclaredTypes() throws FMILException {
782         synchronized(syncObject) {
783
784             try {
785
786                 if(declaredTypes == null) {
787                         declaredTypes = getAllDeclaredTypes_(getModelIDNew());
788                 }
789                 return declaredTypes;
790
791             } catch (UnsatisfiedLinkError err) {
792                 throw new FMILException(UNSATISFIED_LINK);
793             } catch (Exception e) {
794                 throw new FMILException(e.getMessage());
795             }
796         }
797     }
798
799     private native String[] getAllDeclaredTypes_(int id);
800     
801     public String[] getAllDeclaredTypeDescriptions() throws FMILException {
802         synchronized(syncObject) {
803
804             try {
805
806                 if(declaredTypeDescriptions == null) {
807                         declaredTypeDescriptions = getAllDeclaredTypeDescriptions_(getModelIDNew());
808                 }
809                 return declaredTypeDescriptions;
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[] getAllDeclaredTypeDescriptions_(int id);
820     
821     public String[] getAllDeclaredTypeQuantities() throws FMILException {
822         synchronized(syncObject) {
823
824             try {
825
826                 if(declaredTypeQuantities == null) {
827                         declaredTypeQuantities = getAllDeclaredTypeQuantities_(getModelIDNew());
828                 }
829                 return declaredTypeQuantities;
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[] getAllDeclaredTypeQuantities_(int id);
840
841     public String[] getAllDeclaredTypeUnits() throws FMILException {
842         synchronized(syncObject) {
843
844             try {
845
846                 if(declaredTypeUnits == null) {
847                         declaredTypeUnits = getAllDeclaredTypeUnits_(getModelIDNew());
848                 }
849                 return declaredTypeUnits;
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[] getAllDeclaredTypeUnits_(int id);
860     
861     
862 //
863 //    /**
864 //     * Get all variables from model that match the filter (and time variable)
865 //     * 
866 //     * @param regexp Regular expression filter
867 //     * @return An array of variable names that match regexp filter (and time-variable)
868 //     * @throws FMILException
869 //     */
870 //    public String[] filterVariables(String regexp) throws FMILException {       
871 //        synchronized(syncObject) {
872 //            try {
873 //
874 //                return filterVariables_(getModelID(), regexp + "|time");
875 //
876 //            } catch (UnsatisfiedLinkError err) {
877 //                throw new FMILException(UNSATISFIED_LINK);
878 //            } catch (Exception e) {
879 //                throw new FMILException(e.getMessage());
880 //            }
881 //        }
882 //    }
883 //
884 //    private native String[] filterVariables_(String id, String regexp);
885 ////
886 //    /**
887 //     * Get the last error message
888 //     * @return Last error message
889 //     */
890 //    public String getLastErrorMessage() throws FMILException {
891 //        synchronized(syncObject) {
892 //
893 //            try {
894 //
895 //              return "err";
896 //                //return getLastErrorMessage_(getModelID());
897 //
898 //            } catch (UnsatisfiedLinkError err) {
899 //                throw new FMILException(UNSATISFIED_LINK);
900 //            } catch (Exception e) {
901 //                throw new FMILException(e.getMessage());
902 //            }
903 //        }
904 //    }
905 //
906 //    private native String getLastErrorMessage_(String id);
907
908     /**
909      * Get a value (double) for real variable
910      * @param name Name of the variable
911      * @return value
912      * @throws FMILException
913      */
914     public double getRealValue(String name) throws FMILException {
915         double result = getRealValue(variableMap.get(name)); 
916         if (DEBUG) System.err.println("getRealValue " + name + " = " + result);
917         return result;
918     }
919
920     /**
921      * Get a value (double) for real variable
922      * @param variableReference  Numeric id of the variable
923      * @return value
924      * @throws FMILException
925      */
926     public double getRealValue(int variableReference) throws FMILException {
927         synchronized(syncObject) {
928             try {
929                 return getRealValue_(getModelIDNew(), variableReference);
930             } catch (UnsatisfiedLinkError err) {
931                 throw new FMILException(UNSATISFIED_LINK);
932             } catch (Exception e) {
933                 throw new FMILException(e.getMessage());
934             }
935         }
936     }
937     
938     private native double getRealValue_(int id, int variableReference) throws FMILException;
939
940
941     /**
942      * Get value of integer variable
943      * @param name Name of the variable
944      * @return value
945      * @throws FMILException
946      */
947     public int getIntegerValue(String name) throws FMILException {
948         int result = getIntegerValue(variableMap.get(name));
949         if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
950         return result;
951     }
952
953     /**
954      * Get a real (double) value for variable
955      * @param variableReference  Numeric id of the variable
956      * @return value
957      * @throws FMILException
958      */
959     public int getIntegerValue(int variableReference) throws FMILException {
960         synchronized(syncObject) {
961             try {
962                 return getIntegerValue_(getModelIDNew(), variableReference);
963             } catch (UnsatisfiedLinkError err) {
964                 throw new FMILException(UNSATISFIED_LINK);
965             } catch (Exception e) {
966                 throw new FMILException(e.getMessage());
967             }
968         }
969     }
970     
971     private native int getIntegerValue_(int id, int variableReference) throws FMILException;
972     
973     
974     /**
975      * Get value of boolean variable
976      * @param name Name of the variable
977      * @return value
978      * @throws FMILException
979      */
980     public boolean getBooleanValue(String name) throws FMILException {
981         boolean result = getBooleanValue(variableMap.get(name));
982         if (DEBUG) System.err.println("getBooleanValue " + name + " = " + result);
983         return result;
984     }
985
986     /**
987      * Get value of boolean variable
988      * @param variableReference  Numeric id of the variable
989      * @return value
990      * @throws FMILException
991      */
992     public boolean getBooleanValue(int variableReference) throws FMILException {
993         synchronized(syncObject) {
994             try {
995                 return getBooleanValue_(getModelIDNew(), variableReference);
996             } catch (UnsatisfiedLinkError err) {
997                 throw new FMILException(UNSATISFIED_LINK);
998             } catch (Exception e) {
999                 throw new FMILException(e.getMessage());
1000             }
1001         }
1002     }
1003     
1004     private native boolean getBooleanValue_(int id, int variableReference) throws FMILException;
1005     
1006     
1007     /**
1008      * Get value of string variable
1009      * @param name Name of the variable
1010      * @return value
1011      * @throws FMILException
1012      */
1013     public String getStringValue(String name) throws FMILException {
1014         String result = getStringValue(variableMap.get(name));
1015         if (DEBUG) System.err.println("getIntegerValue " + name + " = " + result);
1016         return result;
1017     }
1018
1019     /**
1020      * Get value of string variable
1021      * @param variableReference  Numeric id of the variable
1022      * @return value
1023      * @throws FMILException
1024      */
1025     public String getStringValue(int variableReference) throws FMILException {
1026         synchronized(syncObject) {
1027             try {
1028                 return getStringValue_(getModelIDNew(), variableReference);
1029             } catch (UnsatisfiedLinkError err) {
1030                 throw new FMILException(UNSATISFIED_LINK);
1031             } catch (Exception e) {
1032                 throw new FMILException(e.getMessage());
1033             }
1034         }
1035     }
1036     
1037     private native String getStringValue_(int id, int variableReference) throws FMILException;
1038     
1039
1040     private FileChannel channel; 
1041     private FileLock lock;
1042
1043     @SuppressWarnings("resource")
1044     private boolean lockFMUDirectory() {
1045
1046         try {
1047             // Get a file channel for the lock file
1048             File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME);
1049             if(!lockFile.isFile())
1050                 lockFile.createNewFile();
1051
1052             channel = new RandomAccessFile(lockFile, "rw").getChannel();
1053
1054             // Use the file channel to create a lock on the file.
1055             // This method blocks until it can retrieve the lock.
1056             lock = channel.lock();
1057
1058             //          // Try acquiring the lock without blocking. This method returns
1059             //          // null or throws an exception if the file is already locked.
1060             //          try {
1061             //              lock = channel.tryLock();
1062             //          } catch (OverlappingFileLockException e) {
1063             //              // File is already locked in this thread or virtual machine
1064             //          }
1065         } catch (IOException e) {
1066             return false;
1067         }
1068
1069         return true;
1070     }
1071
1072     private boolean unlockFMUDirectory() {
1073         try {
1074             // Release the lock
1075             if(lock != null)
1076                 lock.release();
1077
1078             // Close the file
1079             if(channel != null)
1080                 channel.close();
1081         } catch (IOException e) {
1082             return false;
1083         }
1084         return true;
1085     }
1086
1087     private boolean removeFMUDirectoryContents() {
1088         // Remove contents
1089         try {
1090             File tempDir = new File(TEMP_FMU_DIRECTORY);
1091             FileUtils.deleteAll(tempDir);
1092             tempDir.delete();
1093         } catch (IOException e) {
1094             return false;
1095         }
1096         return true;
1097     }
1098     
1099     @Override
1100     protected void finalize() throws Throwable {
1101         try {
1102             unloadFMU();
1103         } catch (Throwable t) {
1104             LOGGER.error("Could not unload native FMU!", t);
1105         } finally {
1106             super.finalize();
1107         }
1108     }
1109 }