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