]> gerrit.simantics Code Review - simantics/3d.git/blob - vtk/src/vtk/vtkJavaMemoryManagerImpl.java
Merge "Publish Plant3D feature"
[simantics/3d.git] / vtk / src / vtk / vtkJavaMemoryManagerImpl.java
1 package vtk;
2
3 import java.lang.ref.WeakReference;
4 import java.lang.reflect.Constructor;
5 import java.util.HashMap;
6 import java.util.TreeSet;
7 import java.util.concurrent.locks.ReentrantLock;
8
9 /**
10  * Provide a Java thread safe implementation of vtkJavaMemoryManager. This does
11  * not make VTK thread safe. This only insure that the change of reference count
12  * will never happen in two concurrent thread in the Java world.
13  *
14  * @see vtkJavaMemoryManager
15  * @author sebastien jourdain - sebastien.jourdain@kitware.com
16  */
17 public class vtkJavaMemoryManagerImpl implements vtkJavaMemoryManager {
18     private vtkJavaGarbageCollector garbageCollector;
19     private ReentrantLock lock;
20     private vtkReferenceInformation lastGcResult;
21     private HashMap<Long, WeakReference<vtkObjectBase>> objectMap;
22     private HashMap<Long, String> objectMapClassName;
23
24     public vtkJavaMemoryManagerImpl() {
25         this.lock = new ReentrantLock();
26         this.objectMap = new HashMap<Long, WeakReference<vtkObjectBase>>();
27         this.objectMapClassName = new HashMap<Long, String>();
28         this.garbageCollector = new vtkJavaGarbageCollector();
29     }
30
31     // Thread safe
32     public vtkObjectBase getJavaObject(Long vtkId) {
33         // Check pre-condition
34         if (vtkId == null || vtkId.longValue() == 0) {
35             throw new RuntimeException("Invalid ID, can not be null or equal to 0.");
36         }
37
38         // Check inside the map if the object is already there
39         WeakReference<vtkObjectBase> value = objectMap.get(vtkId);
40         vtkObjectBase resultObject = (value == null) ? null : value.get();
41
42         // If not, we have to do something
43         if (value == null || resultObject == null) {
44             try {
45                 // Make sure no concurrency could happen inside that
46                 this.lock.lock();
47
48                 // Now that we have the lock make sure someone else didn't
49                 // create the object in between, if so just return the created
50                 // instance
51                 value = objectMap.get(vtkId);
52                 resultObject = (value == null) ? null : value.get();
53                 if (resultObject != null) {
54                     return resultObject;
55                 }
56
57                 // We need to do the work of the gc
58                 if (value != null && resultObject == null) {
59                     this.unRegisterJavaObject(vtkId);
60                 }
61
62                 // No-one did create it, so let's do it
63                 if (resultObject == null) {
64                     try {
65                         String className = vtkObjectBase.VTKGetClassNameFromReference(vtkId.longValue());
66                         Class c = Class.forName("vtk." + className);
67                         Constructor cons = c.getConstructor(new Class[] { long.class });
68                         resultObject = (vtkObjectBase) cons.newInstance(new Object[] { vtkId });
69                     } catch (Exception e) {
70                         e.printStackTrace();
71                     }
72                 }
73             } finally {
74                 this.lock.unlock();
75             }
76         }
77         return resultObject;
78     }
79
80     // Thread safe
81     public void registerJavaObject(Long id, vtkObjectBase obj) {
82         try {
83             this.lock.lock();
84             this.objectMap.put(id, new WeakReference<vtkObjectBase>(obj));
85             this.objectMapClassName.put(id, obj.GetClassName());
86         } finally {
87             this.lock.unlock();
88         }
89     }
90
91     // Thread safe
92     public void unRegisterJavaObject(Long id) {
93         try {
94             this.lock.lock();
95             this.objectMapClassName.remove(id);
96             WeakReference<vtkObjectBase> value = this.objectMap.remove(id);
97
98             // Prevent double deletion...
99             if (value != null) {
100                 vtkObjectBase.VTKDeleteReference(id.longValue());
101             } else {
102                 throw new RuntimeException("You try to delete a vtkObject that is not referenced in the Java object Map. You may have call Delete() twice.");
103             }
104         } finally {
105             this.lock.unlock();
106         }
107     }
108
109     // Thread safe
110     public vtkReferenceInformation gc(boolean debug) {
111         System.gc();
112         try {
113             this.lock.lock();
114             final vtkReferenceInformation infos = new vtkReferenceInformation(debug);
115             for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
116                 vtkObjectBase obj = this.objectMap.get(id).get();
117                 if (obj == null) {
118                     infos.addFreeObject(this.objectMapClassName.get(id));
119                     this.unRegisterJavaObject(id);
120                 } else {
121                     infos.addKeptObject(this.objectMapClassName.get(id));
122                 }
123             }
124
125             this.lastGcResult = infos;
126             return infos;
127         } finally {
128             this.lock.unlock();
129         }
130     }
131
132     public vtkJavaGarbageCollector getAutoGarbageCollector() {
133         return this.garbageCollector;
134     }
135
136     // Thread safe
137     public int deleteAll() {
138         int size = this.objectMap.size();
139         try {
140             this.lock.lock();
141             for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
142                 this.unRegisterJavaObject(id);
143             }
144         } finally {
145             this.lock.unlock();
146         }
147         return size;
148     }
149
150     public int getSize() {
151         return objectMap.size();
152     }
153
154     public vtkReferenceInformation getLastReferenceInformation() {
155         return this.lastGcResult;
156     }
157 }