Revision ba0d4c2f
Added by Cherian Mathew about 9 years ago
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CacheLoader.java | ||
---|---|---|
17 | 17 |
import java.util.Map; |
18 | 18 |
import java.util.Set; |
19 | 19 |
|
20 |
import javassist.util.proxy.ProxyFactory; |
|
21 | 20 |
import net.sf.ehcache.Cache; |
22 | 21 |
import net.sf.ehcache.Element; |
23 | 22 |
|
24 | 23 |
import org.apache.log4j.Logger; |
25 |
import org.hibernate.collection.spi.PersistentCollection; |
|
26 | 24 |
import org.hibernate.proxy.HibernateProxy; |
27 | 25 |
import org.hibernate.proxy.LazyInitializer; |
28 | 26 |
import org.springframework.util.ReflectionUtils; |
... | ... | |
40 | 38 |
|
41 | 39 |
private static boolean isRecursiveEnabled = true; |
42 | 40 |
|
43 |
private final ICdmCacher cdmCacher;
|
|
41 |
protected final ICdmCacher cdmCacher;
|
|
44 | 42 |
|
45 | 43 |
private final Cache cdmlibModelCache; |
46 | 44 |
|
47 |
private final ICdmCacher cdmServiceCacher; |
|
48 | 45 |
|
49 | 46 |
|
50 | 47 |
public CacheLoader(ICdmCacher cdmCacher) { |
51 |
this(cdmCacher, null); |
|
52 |
} |
|
53 |
|
|
54 |
public CacheLoader(ICdmCacher cdmCacher, ICdmCacher cdmServiceCacher) { |
|
55 | 48 |
this.cdmCacher = cdmCacher; |
56 | 49 |
this.cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache(); |
57 |
this.cdmServiceCacher = cdmServiceCacher; |
|
50 |
|
|
58 | 51 |
} |
59 | 52 |
|
60 | 53 |
|
... | ... | |
218 | 211 |
return null; |
219 | 212 |
} |
220 | 213 |
|
221 |
|
|
222 | 214 |
// start by looking up the cdm entity in the cache |
223 | 215 |
CdmBase cachedCdmEntity = cdmCacher.getFromCache(cdmEntity); |
224 | 216 |
|
... | ... | |
229 | 221 |
if(cachedCdmEntity == cdmEntity) { |
230 | 222 |
return cachedCdmEntity; |
231 | 223 |
} |
232 |
|
|
233 | 224 |
} |
234 | 225 |
|
235 | 226 |
CdmBase loadedCdmBase; |
... | ... | |
248 | 239 |
} |
249 | 240 |
|
250 | 241 |
|
251 |
private CdmBase load(CdmBase cdmEntity) {
|
|
242 |
protected CdmBase load(CdmBase cdmEntity) {
|
|
252 | 243 |
logger.info("loading object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId()); |
253 | 244 |
|
254 | 245 |
cdmEntity = (CdmBase)ProxyUtils.deproxy(cdmEntity); |
255 | 246 |
|
256 |
// start by looking up the cdm entity in the cache |
|
257 |
CdmBase cachedCdmEntity = cdmCacher.getFromCache(cdmEntity); |
|
247 |
cdmCacher.put(cdmEntity); |
|
248 |
|
|
249 |
return cdmCacher.getFromCache(cdmEntity); |
|
258 | 250 |
|
259 |
if(cachedCdmEntity != null) { |
|
260 |
// if cdm entity was found in cache then return ... |
|
261 |
logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists"); |
|
262 |
return cachedCdmEntity; |
|
263 |
} else { |
|
264 |
// ... else save the entity in the cache |
|
265 |
cdmCacher.put(cdmEntity); |
|
266 |
logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache"); |
|
267 |
return cdmEntity; |
|
268 |
} |
|
269 | 251 |
} |
270 | 252 |
|
253 |
|
|
271 | 254 |
private CdmBase loadRecursive(CdmBase cdmEntity, Set<Object> alreadyVisitedEntities, boolean update) { |
272 | 255 |
|
273 | 256 |
CdmBase cachedCdmEntity = load(cdmEntity); |
274 |
if(cdmServiceCacher != null && cdmServiceCacher.exists(cachedCdmEntity)) { |
|
275 |
return cachedCdmEntity; |
|
276 |
} |
|
257 |
|
|
277 | 258 |
|
278 | 259 |
// we want to recursive through the cdmEntity (and not the cachedCdmEntity) |
279 | 260 |
// since there could be new or deleted objects in the cdmEntity sub-graph |
... | ... | |
298 | 279 |
} else { |
299 | 280 |
logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited"); |
300 | 281 |
} |
301 |
|
|
302 | 282 |
} |
303 | 283 |
} |
304 | 284 |
} else { |
305 | 285 |
throw new CdmClientCacheException("CdmEntity with class " + cdmEntity.getClass().getName() + " is not found in the cdmlib model cache. " + |
306 | 286 |
"The cache may be corrupted or not in sync with the latest model version" ); |
307 | 287 |
} |
288 |
|
|
308 | 289 |
return cachedCdmEntity; |
309 | 290 |
} |
310 | 291 |
|
... | ... | |
334 | 315 |
} |
335 | 316 |
field.setAccessible(true); |
336 | 317 |
Object o = field.get(cdmEntity); |
337 |
|
|
338 |
if(o != null && o instanceof HibernateProxy) { |
|
339 |
LazyInitializer hli = ((HibernateProxy)o).getHibernateLazyInitializer(); |
|
340 |
if(!hli.isUninitialized()) { |
|
341 |
o = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation(); |
|
342 |
field.set(cdmEntity, o); |
|
343 |
} |
|
344 |
} |
|
345 |
|
|
346 |
if(o != null && o instanceof PersistentCollection) { |
|
347 |
PersistentCollection pc = ((PersistentCollection)o); |
|
348 |
if(pc.wasInitialized()) { |
|
349 |
o = ProxyUtils.getObject(pc); |
|
350 |
field.set(cdmEntity, o); |
|
351 |
} |
|
352 |
} |
|
353 |
|
|
318 |
o = ProxyUtils.deproxy(o); |
|
319 |
field.set(cdmEntity, o); |
|
354 | 320 |
|
355 | 321 |
CdmBase cdmEntityInSubGraph = null; |
356 | 322 |
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 |
} |
|
362 |
if(o != null |
|
363 |
&& !ProxyFactory.isProxyClass(o.getClass()) |
|
364 |
&& !(o instanceof PersistentCollection) ) { |
|
365 |
|
|
323 |
// if we are in update mode we have to make the field of the cached entity |
|
324 |
// up-to-date by setting it to the value of the cdm entity being loaded |
|
325 |
// NOTE : two exceptions to this are found below |
|
326 |
field.set(cachedCdmEntity, o); |
|
366 | 327 |
|
328 |
} |
|
329 |
if(o != null && !ProxyUtils.isProxy(o)) { |
|
367 | 330 |
if(CdmBase.class.isAssignableFrom(o.getClass())) { |
368 | 331 |
logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId()); |
369 | 332 |
cdmEntityInSubGraph = (CdmBase)o; |
370 | 333 |
CdmBase cachedCdmEntityInSubGraph = cdmCacher.getFromCache(cdmEntityInSubGraph); |
371 | 334 |
|
372 |
// the only exception to updating the field to the latest value |
|
373 |
// is the case where the field has been already initialised, cached and |
|
374 |
// is not the same as the one in the cache, in which case we set the value |
|
375 |
// of the field to the one found in the cache |
|
335 |
Object oldCachedCdmEntityInSubGraph = field.get(cachedCdmEntity); |
|
336 |
if(ProxyUtils.isProxy(oldCachedCdmEntityInSubGraph)) { |
|
337 |
LazyInitializer hli = |
|
338 |
((HibernateProxy)oldCachedCdmEntityInSubGraph).getHibernateLazyInitializer(); |
|
339 |
|
|
340 |
if(cdmEntityInSubGraph.getId() == ((Integer)hli.getIdentifier()).intValue()) { |
|
341 |
// exception 1 : is the case where |
|
342 |
// the earlier value of the field in the cached entity |
|
343 |
// was a proxy with the same id then we don't need to |
|
344 |
// update it here as it will be updated on demand, |
|
345 |
// so we reset it to the earlier proxy |
|
346 |
field.set(cachedCdmEntity, oldCachedCdmEntityInSubGraph); |
|
347 |
return null; |
|
348 |
} |
|
349 |
} |
|
350 |
|
|
376 | 351 |
if(cachedCdmEntityInSubGraph != null) { |
377 | 352 |
if(cachedCdmEntityInSubGraph != cdmEntityInSubGraph) { |
353 |
// exception 2 : is the case where |
|
354 |
// the field has been already initialised, cached and |
|
355 |
// is not the same as the one in the cache, in which case we set the value |
|
356 |
// of the field to the one found in the cache |
|
378 | 357 |
logger.info("setting cached + real value to '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId()); |
379 | 358 |
field.set(cachedCdmEntity, cachedCdmEntityInSubGraph); |
380 | 359 |
field.set(cdmEntity, cachedCdmEntityInSubGraph); |
381 | 360 |
} else { |
382 |
// hack to stop the recursion, since the field value object in cdmEntity
|
|
361 |
// since the field value object in cdmEntity |
|
383 | 362 |
// is the same as the field value object in cachedCdmEntity |
384 |
cdmEntityInSubGraph = null; |
|
363 |
// we are sure that the its subgraph is also correctly loaded, |
|
364 |
// so we can exit the recursion |
|
365 |
return null; |
|
385 | 366 |
} |
386 | 367 |
} |
387 |
|
|
388 | 368 |
} else if(o instanceof Map && !alreadyVisitedEntities.contains(o)) { |
389 | 369 |
loadRecursive((Map)o, alreadyVisitedEntities, update); |
390 | 370 |
} else if(o instanceof Collection && !alreadyVisitedEntities.contains(o)) { |
Also available in: Unified diff
httpInvokerServiceClients.xml : set 'CdmServiceRequestExecutor' class as default for all services
ICdmEntitySession, CdmEntitySession, MockCdmEntitySession : added method to update session
ICdmEntitySessionManager, CdmEntitySessionManager, MockCdmEntitySessionManager : added methods to set active session, dispose and update sessions
ProxyUtils : added utility method
EntityCacherDebugResult : corrected method to determine cache corresponding to entity
CdmTransientEntityCacher : corrected put method
CacheLoader : optimised recursive call
CdmServiceCacher : corrected methods to get from cache and load
CdmServiceRequestExecutor : added update result return calls to load