prevent and keep track of which objects handling element/jv obj synchronizations.
[jalview.git] / src / jalview / io / vamsas / DatastoreRegistry.java
1 package jalview.io.vamsas;
2
3 import java.util.Enumeration;
4 import java.util.IdentityHashMap;
5 import java.util.Iterator;
6 import java.util.Map;
7
8 import uk.ac.vamsas.client.Vobject;
9
10 public class DatastoreRegistry
11 {
12   protected static org.apache.log4j.Logger log = org.apache.log4j.Logger
13           .getLogger(DatastoreRegistry.class);
14
15   /**
16    * map between Datastore objects and the objects they are handling- used to
17    * prevent cycles in the synchronization pattern. Keys are both vamsas objects
18    * and jalview objects, values are datastore objects.
19    */
20   IdentityHashMap dsObjReg;
21
22   /**
23    * all datastore items - value is [jvObject,vObject]
24    */
25   IdentityHashMap dsItemReg;
26
27   public DatastoreRegistry()
28   {
29     dsObjReg = new IdentityHashMap();
30     dsItemReg = new IdentityHashMap();
31   }
32
33   /**
34    * 
35    * @param obj
36    * @return true if obj is in the registry
37    */
38   public boolean isInvolvedInDsitem(Object obj)
39   {
40     return (obj instanceof DatastoreItem) ? dsItemReg.containsKey(obj)
41             : dsObjReg.containsKey(obj);
42   }
43
44   /**
45    * 
46    * @param obj
47    * @return DatastoreItem associated with obj - or null
48    */
49   public DatastoreItem getDatastoreItemFor(Object obj)
50   {
51     if (obj instanceof DatastoreItem)
52     {
53       log.debug("Returning DatastoreItem self reference.");// TODO: we could
54                                                            // store the update
55                                                            // hierarchy - so
56                                                            // retrieve parent
57                                                            // for obj.
58       return (DatastoreItem) obj;
59     }
60     return (DatastoreItem) dsObjReg.get(obj);
61   }
62
63   public void registerDsObj(DatastoreItem dsitem)
64   {
65     synchronized (dsItemReg)
66     {
67       Object[] dsregitem = (Object[]) dsItemReg.get(dsitem);
68       if (dsregitem == null)
69       {
70         // create a new item entry
71         dsregitem = new Object[]
72         { dsitem.jvobj, dsitem.vobj };
73         dsItemReg.put(dsitem, dsregitem);
74       }
75       // atomic update of the jv and vobject references in the dsObjReg
76       synchronized (dsObjReg)
77       {
78         // for the jvobject
79         if (dsitem.jvobj != dsregitem[0])
80         {
81           // overwrite existing involved entries.
82           if (dsregitem[0] != null)
83           {
84             dsObjReg.remove(dsregitem[0]);
85           }
86           if ((dsregitem[0] = dsitem.jvobj) != null)
87           {
88             dsObjReg.put(dsregitem[0], dsitem);
89           }
90         }
91         // and for the vobject
92         if (dsitem.vobj != dsregitem[1])
93         {
94           // overwrite existing involved entries.
95           if (dsregitem[1] != null)
96           {
97             dsObjReg.remove(dsregitem[1]);
98           }
99           if ((dsregitem[1] = dsitem.vobj) != null)
100           {
101             dsObjReg.put(dsregitem[1], dsitem);
102           }
103         }
104       }
105     }
106   }
107
108   /**
109    * Remove dsitem from the registry
110    * 
111    * @param dsitem
112    * @return null or last known Object[] { jvobject, vobject } references for
113    *         this dsitem
114    */
115   public Object[] removeDsObj(DatastoreItem dsitem)
116   {
117     Object[] dsregitem = null;
118     synchronized (dsItemReg)
119     {
120       synchronized (dsObjReg)
121       {
122         dsregitem = (Object[]) dsItemReg.remove(dsitem);
123         if (dsregitem != null)
124         {
125           // eliminate object refs too
126           if (dsregitem[0] != null)
127           {
128             dsObjReg.remove(dsregitem[0]);
129           }
130           if (dsregitem[1] != null)
131           {
132             dsObjReg.remove(dsregitem[1]);
133           }
134         }
135       }
136     }
137     return dsregitem;
138   }
139
140   protected void finalize()
141   {
142     if (dsObjReg != null)
143     {
144       Iterator items = dsObjReg.entrySet().iterator();
145       // avoid the nested reference memory leak.
146       while (items.hasNext())
147       {
148         Object[] vals = (Object[]) ((Map.Entry) items.next()).getValue();
149         vals[0] = null;
150         vals[1] = null;
151       }
152       items = null;
153       dsObjReg.clear();
154     }
155     if (dsItemReg!=null)
156     {
157       dsItemReg.clear();
158     }
159   }
160 }