Revision 348d552a
Added by Cherian Mathew about 9 years ago
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CacheLoader.java | ||
---|---|---|
44 | 44 |
|
45 | 45 |
private final Cache cdmlibModelCache; |
46 | 46 |
|
47 |
private final ICdmCacher cdmServiceCacher; |
|
48 |
|
|
47 | 49 |
|
48 | 50 |
public CacheLoader(ICdmCacher cdmCacher) { |
51 |
this(cdmCacher, null); |
|
52 |
} |
|
53 |
|
|
54 |
public CacheLoader(ICdmCacher cdmCacher, ICdmCacher cdmServiceCacher) { |
|
49 | 55 |
this.cdmCacher = cdmCacher; |
50 | 56 |
this.cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache(); |
57 |
this.cdmServiceCacher = cdmServiceCacher; |
|
51 | 58 |
} |
52 | 59 |
|
53 | 60 |
|
... | ... | |
61 | 68 |
} |
62 | 69 |
|
63 | 70 |
@SuppressWarnings("unchecked") |
64 |
public <T extends Object> T load(T obj, boolean recursive) { |
|
71 |
public <T extends Object> T load(T obj, boolean recursive, boolean update) {
|
|
65 | 72 |
if(obj == null) { |
66 | 73 |
return null; |
67 | 74 |
} |
68 | 75 |
if(obj instanceof CdmBase) { |
69 |
return (T) load((CdmBase)obj, recursive); |
|
76 |
return (T) load((CdmBase)obj, recursive, update);
|
|
70 | 77 |
} else if (obj instanceof Map) { |
71 |
return (T) load((Map<T,T>)obj, recursive); |
|
78 |
return (T) load((Map<T,T>)obj, recursive, update);
|
|
72 | 79 |
} else if (obj instanceof Collection) { |
73 |
return (T) load((Collection<T>)obj, recursive); |
|
80 |
return (T) load((Collection<T>)obj, recursive, update);
|
|
74 | 81 |
} |
75 | 82 |
|
76 | 83 |
return obj; |
77 | 84 |
} |
78 | 85 |
|
79 | 86 |
@SuppressWarnings("unchecked") |
80 |
private <T extends Object> T loadRecursive(T obj, Set<CdmBase> alreadyVisitedEntities) {
|
|
87 |
private <T extends Object> T loadRecursive(T obj, Set<Object> alreadyVisitedEntities, boolean update) {
|
|
81 | 88 |
if(obj == null) { |
82 | 89 |
return null; |
83 | 90 |
} |
84 | 91 |
if(obj instanceof CdmBase) { |
85 |
return (T) loadRecursive((CdmBase)obj, alreadyVisitedEntities); |
|
92 |
return (T) loadRecursive((CdmBase)obj, alreadyVisitedEntities, update);
|
|
86 | 93 |
} else if (obj instanceof Map) { |
87 |
return (T) load((Map<T,T>)obj, alreadyVisitedEntities); |
|
94 |
return (T) load((Map<T,T>)obj, alreadyVisitedEntities, update);
|
|
88 | 95 |
} else if (obj instanceof Collection) { |
89 |
return (T) load((Collection<T>)obj, alreadyVisitedEntities); |
|
96 |
return (T) load((Collection<T>)obj, alreadyVisitedEntities, update);
|
|
90 | 97 |
} |
91 | 98 |
|
92 | 99 |
|
... | ... | |
95 | 102 |
return obj; |
96 | 103 |
} |
97 | 104 |
|
98 |
public <T extends Object> Map<T,T> load(Map<T,T> map, boolean recursive){ |
|
99 |
if(map == null) { |
|
100 |
return null; |
|
101 |
} |
|
105 |
public <T extends Object> Map<T,T> load(Map<T,T> map, boolean recursive, boolean update){ |
|
106 |
|
|
102 | 107 |
|
103 | 108 |
if(isRecursiveEnabled && recursive) { |
104 | 109 |
logger.info("---- starting recursive load for cdm entity map"); |
105 |
Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
|
|
106 |
Map<T,T> cachedMap = load(map, alreadyVisitedEntities); |
|
110 |
Set<Object> alreadyVisitedEntities = new HashSet<Object>();
|
|
111 |
Map<T,T> cachedMap = load(map, alreadyVisitedEntities, update);
|
|
107 | 112 |
alreadyVisitedEntities.clear(); |
108 | 113 |
logger.info("---- ending recursive load for cdm entity map \n"); |
109 | 114 |
return cachedMap; |
110 | 115 |
} else { |
111 |
return load(map, null); |
|
116 |
return load(map, null, update);
|
|
112 | 117 |
} |
113 | 118 |
} |
114 | 119 |
|
115 | 120 |
|
116 |
private <T extends Object> Map<T,T> load(Map<T,T> map, Set<CdmBase> alreadyVisitedEntities){ |
|
121 |
private <T extends Object> Map<T,T> load(Map<T,T> map, Set<Object> alreadyVisitedEntities, boolean update){ |
|
122 |
//map = (Map<T,T>)deproxy(map); |
|
123 |
|
|
117 | 124 |
if(map == null || map.isEmpty()) { |
118 | 125 |
return map; |
119 | 126 |
} |
... | ... | |
122 | 129 |
Object[] result = new Object[ map.size() * 2 ]; |
123 | 130 |
Iterator<Map.Entry<T,T>> iter = map.entrySet().iterator(); |
124 | 131 |
int i=0; |
132 |
// to avoid ConcurrentModificationException |
|
133 |
alreadyVisitedEntities.add(map); |
|
125 | 134 |
while ( iter.hasNext() ) { |
126 | 135 |
Map.Entry<T,T> e = iter.next(); |
127 | 136 |
result[i++] = e.getKey(); |
... | ... | |
130 | 139 |
|
131 | 140 |
for(i=0; i<result.length;i++) { |
132 | 141 |
if(alreadyVisitedEntities == null) { |
133 |
result[i] = load(result[i], false); |
|
142 |
result[i] = load(result[i], false, update);
|
|
134 | 143 |
} else { |
135 |
result[i] = loadRecursive(result[i], alreadyVisitedEntities); |
|
144 |
result[i] = loadRecursive(result[i], alreadyVisitedEntities, update);
|
|
136 | 145 |
} |
137 | 146 |
} |
138 | 147 |
map.clear(); |
... | ... | |
145 | 154 |
return map; |
146 | 155 |
} |
147 | 156 |
|
148 |
public <T extends Object> Collection<T> load(Collection<T> collection, boolean recursive){ |
|
149 |
if(collection == null) { |
|
150 |
return null; |
|
151 |
} |
|
157 |
public <T extends Object> Collection<T> load(Collection<T> collection, boolean recursive, boolean update){ |
|
152 | 158 |
|
153 | 159 |
Collection<T> loadedCollection; |
154 | 160 |
if(isRecursiveEnabled && recursive) { |
155 | 161 |
logger.info("---- starting recursive load for cdm entity collection"); |
156 |
Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
|
|
157 |
Collection<T> cachedCollection = load(collection, alreadyVisitedEntities); |
|
162 |
Set<Object> alreadyVisitedEntities = new HashSet<Object>();
|
|
163 |
Collection<T> cachedCollection = load(collection, alreadyVisitedEntities, update);
|
|
158 | 164 |
alreadyVisitedEntities.clear(); |
159 | 165 |
logger.info("---- ending recursive load for cdm entity collection \n"); |
160 | 166 |
loadedCollection = cachedCollection; |
161 | 167 |
} else { |
162 |
loadedCollection = load(collection, null); |
|
168 |
loadedCollection = load(collection, null, update);
|
|
163 | 169 |
} |
164 | 170 |
return loadedCollection; |
165 | 171 |
} |
166 | 172 |
|
167 | 173 |
@SuppressWarnings("unchecked") |
168 |
private <T extends Object> Collection<T> load(Collection<T> collection, Set<CdmBase> alreadyVisitedEntities){ |
|
174 |
private <T extends Object> Collection<T> load(Collection<T> collection, Set<Object> alreadyVisitedEntities, boolean update) { |
|
175 |
|
|
176 |
|
|
177 |
|
|
178 |
if(collection == null || collection.isEmpty()) { |
|
179 |
return collection; |
|
180 |
} |
|
169 | 181 |
int length = collection.size(); |
170 | 182 |
Object[] result = new Object[length]; |
171 | 183 |
Iterator<T> collectionItr = collection.iterator(); |
172 | 184 |
int count = 0; |
185 |
// to avoid ConcurrentModificationException |
|
186 |
alreadyVisitedEntities.add(collection); |
|
173 | 187 |
while(collectionItr.hasNext()) { |
174 | 188 |
Object obj = collectionItr.next(); |
175 | 189 |
if(alreadyVisitedEntities == null) { |
176 |
result[count] = load(obj, false); |
|
190 |
result[count] = load(obj, false, update);
|
|
177 | 191 |
} else { |
178 |
result[count] = loadRecursive(obj, alreadyVisitedEntities); |
|
192 |
result[count] = loadRecursive(obj, alreadyVisitedEntities, update);
|
|
179 | 193 |
} |
180 | 194 |
|
181 | 195 |
count++; |
... | ... | |
199 | 213 |
* @param uuid |
200 | 214 |
* @param cdmEntity |
201 | 215 |
*/ |
202 |
public CdmBase load(CdmBase cdmEntity, boolean recursive) { |
|
216 |
public CdmBase load(CdmBase cdmEntity, boolean recursive, boolean update) {
|
|
203 | 217 |
if(cdmEntity == null) { |
204 | 218 |
return null; |
205 | 219 |
} |
... | ... | |
215 | 229 |
if(cachedCdmEntity == cdmEntity) { |
216 | 230 |
return cachedCdmEntity; |
217 | 231 |
} |
218 |
return cachedCdmEntity; |
|
232 |
|
|
219 | 233 |
} |
220 | 234 |
|
221 | 235 |
CdmBase loadedCdmBase; |
222 | 236 |
if(isRecursiveEnabled && recursive) { |
223 | 237 |
logger.info("---- starting recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId()); |
224 |
Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
|
|
225 |
CdmBase cb = loadRecursive(cdmEntity, alreadyVisitedEntities); |
|
238 |
Set<Object> alreadyVisitedEntities = new HashSet<Object>();
|
|
239 |
CdmBase cb = loadRecursive(cdmEntity, alreadyVisitedEntities, update);
|
|
226 | 240 |
alreadyVisitedEntities.clear(); |
227 | 241 |
logger.info("---- ending recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + "\n"); |
228 | 242 |
loadedCdmBase = cb; |
... | ... | |
237 | 251 |
private CdmBase load(CdmBase cdmEntity) { |
238 | 252 |
logger.info("loading object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId()); |
239 | 253 |
|
254 |
cdmEntity = (CdmBase)ProxyUtils.deproxy(cdmEntity); |
|
255 |
|
|
240 | 256 |
// start by looking up the cdm entity in the cache |
241 | 257 |
CdmBase cachedCdmEntity = cdmCacher.getFromCache(cdmEntity); |
242 | 258 |
|
... | ... | |
252 | 268 |
} |
253 | 269 |
} |
254 | 270 |
|
255 |
private CdmBase loadRecursive(CdmBase cdmEntity, Set<CdmBase> alreadyVisitedEntities) {
|
|
271 |
private CdmBase loadRecursive(CdmBase cdmEntity, Set<Object> alreadyVisitedEntities, boolean update) {
|
|
256 | 272 |
|
257 | 273 |
CdmBase cachedCdmEntity = load(cdmEntity); |
258 |
|
|
274 |
if(cdmServiceCacher != null && cdmServiceCacher.exists(cachedCdmEntity)) { |
|
275 |
return cachedCdmEntity; |
|
276 |
} |
|
259 | 277 |
|
260 | 278 |
// we want to recursive through the cdmEntity (and not the cachedCdmEntity) |
261 | 279 |
// since there could be new or deleted objects in the cdmEntity sub-graph |
... | ... | |
271 | 289 |
// this object will be either a CdmBase or a Collection / Map |
272 | 290 |
// with CdmBase as the generic type |
273 | 291 |
|
274 |
CdmBase cdmEntityInSubGraph = getCdmBaseTypeFieldValue(cdmEntity, cachedCdmEntity, field, alreadyVisitedEntities); |
|
292 |
CdmBase cdmEntityInSubGraph = getCdmBaseTypeFieldValue(cdmEntity, cachedCdmEntity, field, alreadyVisitedEntities, update);
|
|
275 | 293 |
if(cdmEntityInSubGraph != null) { |
276 | 294 |
//checkForIdenticalCdmEntity(alreadyVisitedEntities, cdmEntityInSubGraph); |
277 | 295 |
if(!alreadyVisitedEntities.contains(cdmEntityInSubGraph)) { |
278 | 296 |
logger.info("recursive loading object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId()); |
279 |
loadRecursive(cdmEntityInSubGraph, alreadyVisitedEntities); |
|
297 |
loadRecursive(cdmEntityInSubGraph, alreadyVisitedEntities, update);
|
|
280 | 298 |
} else { |
281 | 299 |
logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited"); |
282 | 300 |
} |
... | ... | |
294 | 312 |
private CdmBase getCdmBaseTypeFieldValue(CdmBase cdmEntity, |
295 | 313 |
CdmBase cachedCdmEntity, |
296 | 314 |
String fieldName, |
297 |
Set<CdmBase> alreadyVisitedEntities) { |
|
315 |
Set<Object> alreadyVisitedEntities, |
|
316 |
boolean update) { |
|
298 | 317 |
|
299 | 318 |
// this method attempts to make sure that for any two objects found in |
300 | 319 |
// the object graph, if they are equal then they should also be the same, |
... | ... | |
334 | 353 |
|
335 | 354 |
|
336 | 355 |
CdmBase cdmEntityInSubGraph = null; |
356 |
if(update) { |
|
357 |
// making sure that the field in cached cdm entity is always |
|
358 |
// up-to-date by setting to the value of the cdm entity being loaded |
|
359 |
// the only exception to this is found below |
|
360 |
field.set(cachedCdmEntity, o); |
|
361 |
} |
|
337 | 362 |
if(o != null |
338 | 363 |
&& !ProxyFactory.isProxyClass(o.getClass()) |
339 | 364 |
&& !(o instanceof PersistentCollection) ) { |
340 | 365 |
|
366 |
|
|
341 | 367 |
if(CdmBase.class.isAssignableFrom(o.getClass())) { |
342 | 368 |
logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId()); |
343 | 369 |
cdmEntityInSubGraph = (CdmBase)o; |
344 |
|
|
345 |
|
|
346 | 370 |
CdmBase cachedCdmEntityInSubGraph = cdmCacher.getFromCache(cdmEntityInSubGraph); |
347 |
// making sure that the field in cached cdm entity is always |
|
348 |
// up-to-date by setting to the value of the cdm entity being loaded |
|
349 |
// the only execption to this is found below |
|
350 |
field.set(cachedCdmEntity, o); |
|
351 |
|
|
352 | 371 |
|
353 | 372 |
// the only exception to updating the field to the latest value |
354 | 373 |
// is the case where the field has been already initialised, cached and |
... | ... | |
359 | 378 |
logger.info("setting cached + real value to '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId()); |
360 | 379 |
field.set(cachedCdmEntity, cachedCdmEntityInSubGraph); |
361 | 380 |
field.set(cdmEntity, cachedCdmEntityInSubGraph); |
381 |
} else { |
|
382 |
// hack to stop the recursion, since the field value object in cdmEntity |
|
383 |
// is the same as the field value object in cachedCdmEntity |
|
384 |
cdmEntityInSubGraph = null; |
|
362 | 385 |
} |
363 |
cdmEntityInSubGraph = null; |
|
364 | 386 |
} |
365 | 387 |
|
366 |
} else if(o instanceof Map) { |
|
367 |
loadRecursive((Map)o, alreadyVisitedEntities); |
|
368 |
} else if(o instanceof Collection) { |
|
369 |
loadRecursive((Collection)o, alreadyVisitedEntities); |
|
388 |
} else if(o instanceof Map && !alreadyVisitedEntities.contains(o)) {
|
|
389 |
loadRecursive((Map)o, alreadyVisitedEntities, update);
|
|
390 |
} else if(o instanceof Collection && !alreadyVisitedEntities.contains(o)) {
|
|
391 |
loadRecursive((Collection)o, alreadyVisitedEntities, update);
|
|
370 | 392 |
} |
371 | 393 |
} |
372 | 394 |
// we return the original cdm entity in the sub graph because we |
... | ... | |
398 | 420 |
return false; |
399 | 421 |
} |
400 | 422 |
|
423 |
|
|
401 | 424 |
public static boolean isRecursiveEnabled() { |
402 | 425 |
return isRecursiveEnabled; |
403 | 426 |
} |
Also available in: Unified diff
AbstractPersistentCollection : fixed loading of collection
MockCdmEntitySessionManager, MockCdmEntitySession, ICdmEntitySessionManager, ICdmEntitySession, CdmEntitySessionManager,
CdmEntitySession : added new load method with choice to update client object graph
TermServiceRequestExecutor : using cacher instead of cache
ICachedCommonService, CachedCommonServiceImpl, ProxyUtils : moved utility methods to utility class
CdmServiceRequestExecutor : updating client object graph when calling merge
EntityCacherDebugResult : corrections for output string
CdmTransientEntityCacher : corrected cache configuration, added load methods with update choice, added service cacher check before put
CacheLoader : checking in recursive call if collection and maps are already visited
CdmRemotingException : added constructor with exception as argument
CdmServiceCacher : corrected cache configuration and loading of entities from default cache