37026ba3f76b889f4eebcdf07a4562dde4e23fe5
[jalview.git] / src / jalview / io / vamsas / DatastoreRegistry.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.io.vamsas;
22
23 import java.util.IdentityHashMap;
24 import java.util.Iterator;
25 import java.util.Map;
26
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29
30 public class DatastoreRegistry implements AutoCloseable
31 {
32   protected static Logger log = LogManager
33           .getLogger(DatastoreRegistry.class);
34
35   /**
36    * map between Datastore objects and the objects they are handling- used to
37    * prevent cycles in the synchronization pattern. Keys are both vamsas objects
38    * and jalview objects, values are datastore objects.
39    */
40   IdentityHashMap dsObjReg;
41
42   /**
43    * all datastore items - value is [jvObject,vObject]
44    */
45   IdentityHashMap dsItemReg;
46
47   public DatastoreRegistry()
48   {
49     dsObjReg = new IdentityHashMap();
50     dsItemReg = new IdentityHashMap();
51   }
52
53   /**
54    * 
55    * @param obj
56    * @return true if obj is in the registry
57    */
58   public boolean isInvolvedInDsitem(Object obj)
59   {
60     return (obj instanceof DatastoreItem) ? dsItemReg.containsKey(obj)
61             : dsObjReg.containsKey(obj);
62   }
63
64   /**
65    * 
66    * @param obj
67    * @return DatastoreItem associated with obj - or null
68    */
69   public DatastoreItem getDatastoreItemFor(Object obj)
70   {
71     if (obj instanceof DatastoreItem)
72     {
73       log.debug("Returning DatastoreItem self reference.");// TODO: we could
74       // store the update
75       // hierarchy - so
76       // retrieve parent
77       // for obj.
78       return (DatastoreItem) obj;
79     }
80     return (DatastoreItem) dsObjReg.get(obj);
81   }
82
83   synchronized void registerDsObj(DatastoreItem dsitem)
84   {
85     Object[] dsregitem = (Object[]) dsItemReg.get(dsitem);
86     if (dsregitem == null)
87     {
88       // create a new item entry
89       dsregitem = new Object[] { dsitem.jvobj, dsitem.vobj };
90       dsItemReg.put(dsitem, dsregitem);
91       dsObjReg.put(dsitem.jvobj, dsitem);
92       dsObjReg.put(dsitem.vobj, dsitem);
93     }
94     else
95     {
96       // update registry for any changed references
97       // for the jvobject
98       if (dsitem.jvobj != dsregitem[0])
99       {
100         // overwrite existing involved entries.
101         if (dsregitem[0] != null)
102         {
103           dsObjReg.remove(dsregitem[0]);
104         }
105         if ((dsregitem[0] = dsitem.jvobj) != null)
106         {
107           dsObjReg.put(dsregitem[0], dsitem);
108         }
109       }
110       // and for the vobject
111       if (dsitem.vobj != dsregitem[1])
112       {
113         // overwrite existing involved entries.
114         if (dsregitem[1] != null)
115         {
116           dsObjReg.remove(dsregitem[1]);
117         }
118         if ((dsregitem[1] = dsitem.vobj) != null)
119         {
120           dsObjReg.put(dsregitem[1], dsitem);
121         }
122       }
123     }
124   }
125
126   /**
127    * Remove dsitem from the registry
128    * 
129    * @param dsitem
130    * @return null or last known Object[] { jvobject, vobject } references for
131    *         this dsitem
132    */
133   public synchronized Object[] removeDsObj(DatastoreItem dsitem)
134   {
135     Object[] dsregitem = null;
136     // synchronized (dsItemReg)
137     {
138       // synchronized (dsObjReg)
139       {
140         dsregitem = (Object[]) dsItemReg.remove(dsitem);
141         if (dsregitem != null)
142         {
143           // eliminate object refs too
144           if (dsregitem[0] != null)
145           {
146             dsObjReg.remove(dsregitem[0]);
147           }
148           if (dsregitem[1] != null)
149           {
150             dsObjReg.remove(dsregitem[1]);
151           }
152         }
153       }
154     }
155     return dsregitem;
156   }
157
158   @Override
159   public void close()
160   {
161     if (dsObjReg != null)
162     {
163       Iterator items = dsObjReg.entrySet().iterator();
164       // avoid the nested reference memory leak.
165       while (items.hasNext())
166       {
167         Object[] vals = (Object[]) ((Map.Entry) items.next()).getValue();
168         vals[0] = null;
169         vals[1] = null;
170       }
171       items = null;
172       dsObjReg.clear();
173     }
174     if (dsItemReg != null)
175     {
176       dsItemReg.clear();
177     }
178     // super.finalize();
179   }
180 }