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