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;
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.
14 * @see vtkJavaMemoryManager
15 * @author sebastien jourdain - sebastien.jourdain@kitware.com
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;
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();
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.");
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();
42 // If not, we have to do something
43 if (value == null || resultObject == null) {
45 // Make sure no concurrency could happen inside that
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
51 value = objectMap.get(vtkId);
52 resultObject = (value == null) ? null : value.get();
53 if (resultObject != null) {
57 // We need to do the work of the gc
58 if (value != null && resultObject == null) {
59 this.unRegisterJavaObject(vtkId);
62 // No-one did create it, so let's do it
63 if (resultObject == null) {
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) {
81 public void registerJavaObject(Long id, vtkObjectBase obj) {
84 this.objectMap.put(id, new WeakReference<vtkObjectBase>(obj));
85 this.objectMapClassName.put(id, obj.GetClassName());
92 public void unRegisterJavaObject(Long id) {
95 this.objectMapClassName.remove(id);
96 WeakReference<vtkObjectBase> value = this.objectMap.remove(id);
98 // Prevent double deletion...
100 vtkObjectBase.VTKDeleteReference(id.longValue());
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.");
110 public vtkReferenceInformation gc(boolean debug) {
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();
118 infos.addFreeObject(this.objectMapClassName.get(id));
119 this.unRegisterJavaObject(id);
121 infos.addKeptObject(this.objectMapClassName.get(id));
125 this.lastGcResult = infos;
132 public vtkJavaGarbageCollector getAutoGarbageCollector() {
133 return this.garbageCollector;
137 public int deleteAll() {
138 int size = this.objectMap.size();
141 for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
142 this.unRegisterJavaObject(id);
150 public int getSize() {
151 return objectMap.size();
154 public vtkReferenceInformation getLastReferenceInformation() {
155 return this.lastGcResult;