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