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