]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GECache.java
Fix livelock situation in QueryProcessor
[simantics/platform.git] / bundles / org.simantics.browsing.ui.common / src / org / simantics / browsing / ui / common / internal / GECache.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.browsing.ui.common.internal;
13
14 import gnu.trove.map.hash.THashMap;
15 import gnu.trove.map.hash.TObjectIntHashMap;
16 import gnu.trove.set.hash.THashSet;
17
18 import java.util.Collections;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.simantics.browsing.ui.NodeContext;
23 import org.simantics.browsing.ui.NodeContext.CacheKey;
24
25 public class GECache implements IGECache {
26
27     final Map<GECacheKey, IGECacheEntry> entries = new THashMap<GECacheKey, IGECacheEntry>();
28     final Map<GECacheKey, Set<UIElementReference>> treeReferences = new THashMap<GECacheKey, Set<UIElementReference>>();
29
30     final private static class GECacheKey {
31
32         private NodeContext context;
33         private CacheKey<?> key;
34
35         GECacheKey(NodeContext context, CacheKey<?> key) {
36             this.context = context;
37             this.key = key;
38             if (context == null || key == null) 
39                 throw new IllegalArgumentException("Null context or key is not accepted");
40         }
41
42         GECacheKey(GECacheKey other) {
43             this.context = other.context;
44             this.key = other.key;
45             if (context == null || key == null) 
46                 throw new IllegalArgumentException("Null context or key is not accepted");
47         }
48
49         void setValues(NodeContext context, CacheKey<?> key) {
50             this.context = context;
51             this.key = key;
52             if (context == null || key == null) 
53                 throw new IllegalArgumentException("Null context or key is not accepted");
54         }
55
56         @Override
57         public int hashCode() {
58             return context.hashCode() | key.hashCode();
59         }
60
61         @Override
62         public boolean equals(Object object) {
63
64             if (this == object)
65                 return true;
66             else if (object == null)
67                 return false;
68 //            else if (getClass() != object.getClass())
69 //                return false;
70
71             GECacheKey i = (GECacheKey)object;
72
73             return key.equals(i.key) && context.equals(i.context);
74
75         }
76
77     };
78
79     /**
80      * This single instance is used for all get operations from the cache. This
81      * should work since the GE cache is meant to be single-threaded within the
82      * current UI thread, what ever that thread is. For put operations which
83      * store the key, this is not used.
84      */
85     NodeContext getNC = new NodeContext() {
86                 @Override
87         public <T> T getAdapter(Class<T> adapter) {
88                 return null;
89         }
90         
91         @Override
92         public <T> T getConstant(ConstantKey<T> key) {
93                 return null;
94         }
95         
96         @Override
97         public Set<ConstantKey<?>> getKeys() {
98                 return Collections.emptySet();
99         }
100     };
101     CacheKey<?> getCK = new CacheKey<Object>() {
102         @Override
103         public Object processorIdenfitier() {
104                 return this;
105         }
106         };
107     GECacheKey getKey = new GECacheKey(getNC, getCK);
108
109     public <T> IGECacheEntry put(NodeContext context, CacheKey<T> key, T value) {
110         IGECacheEntry entry = new GECacheEntry(context, key, value);
111         entries.put(new GECacheKey(context, key), entry);
112         return entry;
113     }
114
115     @SuppressWarnings("unchecked")
116     public <T> T get(NodeContext context, CacheKey<T> key) {
117         getKey.setValues(context, key);
118         IGECacheEntry entry = entries.get(getKey);
119         if (entry == null)
120             return null;
121         return (T) entry.getValue();
122     }
123
124     @Override
125     public <T> IGECacheEntry getEntry(NodeContext context, CacheKey<T> key) {
126         assert(context != null);
127         assert(key != null);
128         getKey.setValues(context, key);
129         return entries.get(getKey);
130     }
131
132     @Override
133     public <T> void remove(NodeContext context, CacheKey<T> key) {
134         getKey.setValues(context, key);
135         entries.remove(getKey);
136     }
137
138     @Override
139     public <T> Set<UIElementReference> getTreeReference(NodeContext context, CacheKey<T> key) {
140         assert(context != null);
141         assert(key != null);
142         getKey.setValues(context, key);
143         return treeReferences.get(getKey);
144     }
145
146     @Override
147     public <T> void putTreeReference(NodeContext context, CacheKey<T> key, UIElementReference reference) {
148         assert(context != null);
149         assert(key != null);
150         getKey.setValues(context, key);
151         Set<UIElementReference> refs = treeReferences.get(getKey);
152         if (refs != null) {
153             refs.add(reference);
154         } else {
155             refs = new THashSet<UIElementReference>(4);
156             refs.add(reference);
157             treeReferences.put(new GECacheKey(getKey), refs);
158         }
159     }
160
161     @Override
162     public <T> Set<UIElementReference> removeTreeReference(NodeContext context, CacheKey<T> key) {
163         assert(context != null);
164         assert(key != null);
165         getKey.setValues(context, key);
166         return treeReferences.remove(getKey);
167     }
168     
169     @Override
170     public boolean isShown(NodeContext context) {
171         return references.get(context) > 0;
172     }
173
174     private TObjectIntHashMap<NodeContext> references = new TObjectIntHashMap<NodeContext>();
175     
176     @Override
177     synchronized public void incRef(NodeContext context) {
178         int exist = references.get(context);
179         references.put(context, exist+1);
180     }
181     
182     @Override
183     synchronized public void decRef(NodeContext context) {
184         int exist = references.get(context);
185         references.put(context, exist-1);
186         if(exist == 1) {
187                 references.remove(context);
188         }
189     }
190     
191     public void dispose() {
192         references.clear();
193         entries.clear();
194         treeReferences.clear();
195     }
196     
197 }