File: vtkJavaMemoryManagerImpl.java

package info (click to toggle)
vtk7 7.1.1%2Bdfsg2-8
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 127,396 kB
  • sloc: cpp: 1,539,584; ansic: 124,382; python: 78,038; tcl: 47,013; xml: 8,142; yacc: 5,040; java: 4,439; perl: 3,132; lex: 1,926; sh: 1,500; makefile: 126; objc: 83
file content (157 lines) | stat: -rw-r--r-- 4,888 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package vtk;

import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.TreeSet;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Provide a Java thread safe implementation of vtkJavaMemoryManager. This does
 * not make VTK thread safe. This only insure that the change of reference count
 * will never happen in two concurrent thread in the Java world.
 *
 * @see vtkJavaMemoryManager
 * @author sebastien jourdain - sebastien.jourdain@kitware.com
 */
public class vtkJavaMemoryManagerImpl implements vtkJavaMemoryManager {
  private vtkJavaGarbageCollector garbageCollector;
  private ReentrantLock lock;
  private vtkReferenceInformation lastGcResult;
  private HashMap<Long, WeakReference<vtkObjectBase>> objectMap;
  private HashMap<Long, String> objectMapClassName;

  public vtkJavaMemoryManagerImpl() {
    this.lock = new ReentrantLock();
    this.objectMap = new HashMap<Long, WeakReference<vtkObjectBase>>();
    this.objectMapClassName = new HashMap<Long, String>();
    this.garbageCollector = new vtkJavaGarbageCollector();
  }

  // Thread safe
  public vtkObjectBase getJavaObject(Long vtkId) {
    // Check pre-condition
    if (vtkId == null || vtkId.longValue() == 0) {
      throw new RuntimeException("Invalid ID, can not be null or equal to 0.");
    }

    // Check inside the map if the object is already there
    WeakReference<vtkObjectBase> value = objectMap.get(vtkId);
    vtkObjectBase resultObject = (value == null) ? null : value.get();

    // If not, we have to do something
    if (value == null || resultObject == null) {
      try {
        // Make sure no concurrency could happen inside that
        this.lock.lock();

        // Now that we have the lock make sure someone else didn't
        // create the object in between, if so just return the created
        // instance
        value = objectMap.get(vtkId);
        resultObject = (value == null) ? null : value.get();
        if (resultObject != null) {
          return resultObject;
        }

        // We need to do the work of the gc
        if (value != null && resultObject == null) {
          this.unRegisterJavaObject(vtkId);
        }

        // No-one did create it, so let's do it
        if (resultObject == null) {
          try {
            String className = vtkObjectBase.VTKGetClassNameFromReference(vtkId.longValue());
            Class<?> c = Class.forName("vtk." + className);
            Constructor<?> cons = c.getConstructor(new Class<?>[] { long.class });
            resultObject = (vtkObjectBase) cons.newInstance(new Object[] { vtkId });
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      } finally {
        this.lock.unlock();
      }
    }
    return resultObject;
  }

  // Thread safe
  public void registerJavaObject(Long id, vtkObjectBase obj) {
    try {
      this.lock.lock();
      this.objectMap.put(id, new WeakReference<vtkObjectBase>(obj));
      this.objectMapClassName.put(id, obj.GetClassName());
    } finally {
      this.lock.unlock();
    }
  }

  // Thread safe
  public void unRegisterJavaObject(Long id) {
    try {
      this.lock.lock();
      this.objectMapClassName.remove(id);
      WeakReference<vtkObjectBase> value = this.objectMap.remove(id);

      // Prevent double deletion...
      if (value != null) {
        vtkObjectBase.VTKDeleteReference(id.longValue());
      } else {
        throw new RuntimeException("You try to delete a vtkObject that is not referenced in the Java object Map. You may have call Delete() twice.");
      }
    } finally {
      this.lock.unlock();
    }
  }

  // Thread safe
  public vtkReferenceInformation gc(boolean debug) {
    System.gc();
    try {
      this.lock.lock();
      final vtkReferenceInformation infos = new vtkReferenceInformation(debug);
      for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
        vtkObjectBase obj = this.objectMap.get(id).get();
        if (obj == null) {
          infos.addFreeObject(this.objectMapClassName.get(id));
          this.unRegisterJavaObject(id);
        } else {
          infos.addKeptObject(this.objectMapClassName.get(id));
        }
      }

      this.lastGcResult = infos;
      return infos;
    } finally {
      this.lock.unlock();
    }
  }

  public vtkJavaGarbageCollector getAutoGarbageCollector() {
    return this.garbageCollector;
  }

  // Thread safe
  public int deleteAll() {
    int size = this.objectMap.size();
    try {
      this.lock.lock();
      for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
        this.unRegisterJavaObject(id);
      }
    } finally {
      this.lock.unlock();
    }
    return size;
  }

  public int getSize() {
    return objectMap.size();
  }

  public vtkReferenceInformation getLastReferenceInformation() {
    return this.lastGcResult;
  }
}