Mercurial > hg > openmind
view src/main/java/org/mpi/openmind/cache/CacheService.java @ 75:e0be7c0030f5
cleanup and better comments.
author | casties |
---|---|
date | Thu, 23 Feb 2017 19:05:47 +0100 |
parents | 677492395dc0 |
children |
line wrap: on
line source
package org.mpi.openmind.cache; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.mpi.openmind.repository.bo.Attribute; import org.mpi.openmind.repository.bo.Entity; import org.mpi.openmind.repository.bo.Relation; import org.mpi.openmind.repository.bo.ViewerAttribute; import org.mpi.openmind.repository.bo.ViewerPage; public class CacheService extends AbstractCacheService{ private static Logger logger = Logger.getLogger(CacheService.class); private Map<String, Entity> lwDefs = new HashMap<String, Entity>(); private Map<Long, Map<Long, Attribute>> defAttrs = new HashMap<Long, Map<Long, Attribute>>(); private Map<Long, Relation> defRels = new HashMap<Long, Relation>(); private boolean defsLoaded = false; public CacheService(){ super(); logger.info( "[" + Thread.currentThread().getId() + "]\tInitializing CacheService HashCode=" + this.hashCode()); } /** * Set up definitions. * * @param defs * @param atts * @param rels */ public void initDefinitions(List<Entity> defs, List<Attribute> atts, List<Relation> rels) { for (Entity def : defs) { this.lwDefs.put(def.getOwnValue(), def); } for (Attribute att : atts) { if (!this.defAttrs.containsKey(att.getSourceId())) { this.defAttrs.put(att.getSourceId(), new HashMap<Long, Attribute>()); } this.defAttrs.get(att.getSourceId()).put(att.getId(), att); } for (Relation rel : rels) { this.defRels.put(rel.getId(), rel); } this.defsLoaded = true; } public void saveLWDefinition(Entity definition){ synchronized (lwDefs) { this.lwDefs.put(definition.getOwnValue(), definition); } } public void createLWDefinition(Entity definition){ synchronized (lwDefs) { this.lwDefs.put(definition.getOwnValue(), definition); this.defAttrs.put(definition.getId(), new HashMap<Long, Attribute>()); } } public void saveDefAttribute(Attribute att){ if(!this.defsLoaded){ this.throwDefLoadingException(); return; } synchronized (defAttrs) { if(!this.defAttrs.containsKey(att.getSourceId())){ this.defAttrs.put(att.getSourceId(), new HashMap<Long, Attribute>()); } this.defAttrs.get(att.getSourceId()).put(att.getId(), att); } } public void saveDefRelation(Relation rel){ if(!this.defsLoaded){ this.throwDefLoadingException(); return; } synchronized (defRels) { this.defRels.put(rel.getId(), rel); } } public void deleteDefRelation(Relation rel){ if(!this.defsLoaded){ this.throwDefLoadingException(); return; } synchronized (defRels) { this.defRels.remove(rel.getId()); } } public void deleteDefAttribute(Attribute att){ if(!this.defsLoaded){ this.throwDefLoadingException(); return; } synchronized (defAttrs) { if(this.defAttrs.containsKey(att.getSourceId())){ this.defAttrs.get(att.getSourceId()).remove(att.getId()); } } } public void deleteDefinition(Long defId){ if(!this.defsLoaded){ this.throwDefLoadingException(); return; } Entity lwDef = getLWDefinitionById(defId); if(lwDef != null){ synchronized (lwDefs) { this.lwDefs.remove(lwDef.getOwnValue()); } synchronized (defAttrs) { this.defAttrs.remove(defId); } List<Relation> toRemove = new ArrayList<Relation>(); for(Relation rel : this.defRels.values()){ if(rel.getSourceId().equals(defId) || rel.getTargetId().equals(defId)){ toRemove.add(rel); } } synchronized (defRels) { for(Relation rel : toRemove){ this.defRels.remove(rel.getId()); } } } } public boolean areDefsLoaded(){ return defsLoaded; } public int getEntitiesCount(String def){ return this.loadEntitiesByDef(def).size(); } public void updateRelationAsNode(Relation rel){ this.updateRel(rel); } public Entity getEntityContent(Entity ent) throws Exception{ if(ent.isLightweight()){ boolean valid = false; List<Attribute> atts = getAttsBySrcId(ent.getId()); if(atts != null){ ent.setAttributes(atts); Collection<Relation> srcRels = getRelsBySrcId(ent.getId()); if(srcRels != null){ ent.setSourceRelations(new ArrayList<Relation>(srcRels)); Collection<Relation> tarRels = getRelsByTarId(ent.getId()); if(tarRels != null){ ent.setTargetRelations(new ArrayList<Relation>(tarRels)); ent.setLightweight(false); valid = true; } } } if(valid){ return ent; } } return null; } /** * Returns all (lightweight) definition entities. * * @return */ public List<Entity> getLWDefinitions(){ List<Entity> list = new ArrayList<Entity>(this.lwDefs.values()); Collections.sort(list); return list; } /** * Returns the (lightweight) definition entity for the given type. * * @param objectClass * @return */ public Entity getLWDefinition(String objectClass){ Entity def = this.lwDefs.get(objectClass); return def; } private void throwDefLoadingException(){ try { throw new Exception("the definitions were not loaded"); } catch (Exception e) { logger.error(e); } } /** * Returns the attributes of the definition of the given type. * * @param objectClass * @return */ public List<Attribute> getDefAttributes(String objectClass) { if (!this.defsLoaded) { this.throwDefLoadingException(); return null; } Entity lwDef = getLWDefinition(objectClass); if (lwDef != null) { List<Attribute> list = null; if (this.defAttrs.containsKey(lwDef.getId())) { list = new ArrayList<Attribute>(this.defAttrs.get(lwDef.getId()).values()); Collections.sort(list); } else { list = new ArrayList<Attribute>(); } return list; } return new ArrayList<Attribute>(); } public List<Attribute> getDefAttributesById(Long id){ if(!this.defsLoaded){ this.throwDefLoadingException(); return null; } if(this.defAttrs.containsKey(id)){ List<Attribute> list = new ArrayList<Attribute>(this.defAttrs.get(id).values()); Collections.sort(list); return list; } return new ArrayList<Attribute>(); } /** * Returns the source relations of the definition of the given type. * * @param objectClass * @return */ public List<Relation> getDefSourceRelations(String objectClass){ if(!this.defsLoaded){ this.throwDefLoadingException(); return null; } Entity lwDef = getLWDefinition(objectClass); List<Relation> list = new ArrayList<Relation>(); if(lwDef != null){ for(Relation rel : this.defRels.values()){ if(lwDef.getId().equals(rel.getSourceId())){ list.add(rel); } } } Collections.sort(list); return list; } /** * Returns the target relations of the definition of the given type. * * @param objectClass * @return */ public List<Relation> getDefTargetRelations(String objectClass){ if(!this.defsLoaded){ try { throw new Exception("the definitions were not loaded when getDefTargetRelations"); } catch (Exception e) { e.printStackTrace(); } } Entity lwDef = getLWDefinition(objectClass); List<Relation> list = new ArrayList<Relation>(); if(lwDef != null){ for(Relation rel : this.defRels.values()){ if(lwDef.getId().equals(rel.getTargetId())){ list.add(rel); } } } Collections.sort(list); return list; } public Entity getLWDefinitionById(Long id){ for(Entity def : lwDefs.values()){ if(def.getId().equals(id)){ return def; } } return null; } /** * Puts the entity and its Attributes and Relations in the cache. * * This method should be called when a entity has been changed. * It means that every trail of the old entity will be removed from the cache. * @param ent */ public void saveEntity(Entity ent){ try { logger.debug("Saving in cache " + ent.getObjectClass() + " - " + ent.getId()); this.deleteEntity(ent.getId(), ent.getObjectClass()); this.updateLWEntity(ent); if(!ent.isLightweight()){ this.updateRelList(ent.getSourceRelations()); this.updateRelList(ent.getTargetRelations()); this.updateAttList(ent.getAttributes()); } } catch (Exception e) { logger.error(e.getMessage(), e); } } /** * Remove the Entity and its Attributes and Relations from the cache. * * @param entId * @param oc */ public void deleteEntity(Long entId, String oc){ try { this.removeEntity(entId, oc); List<Attribute> attList = getAttsBySrcId(entId); for(Attribute att : attList){ removeAtt(att); } List<Relation> srcRelList = getRelsBySrcId(entId); for(Relation rel : srcRelList){ this.removeRel(rel); } List<Relation> tarRelList = getRelsByTarId(entId); for(Relation rel : tarRelList){ this.removeRel(rel); } } catch (Exception e) { logger.error(e.getMessage(), e); } } /** * Returns if this Entity and its Attributes and Relations are up-to-date with the cache. * * Checks accessTimes only. * * @param ent * @return */ public boolean isEntityCurrent(Entity ent) { // check entity if (!isLWEntityCurrent(ent)) { return false; } if (ent.isLightweight()) { logger.error("Can not check attributes and relations of lightweight entity!"); return false; } Long entId = ent.getId(); // check attached attributes List<Attribute> entAtts = ent.getAttributes(); List<Attribute> cacheAtts = attMap.getValuesByBKey(entId); for (Attribute att : entAtts) { if (!isAttCurrent(att)) { return false; } else { if (!cacheAtts.remove(att)) { return false; } } } // check additional attributes in cache if (!cacheAtts.isEmpty()) { for (Attribute ca : cacheAtts) { // ignore empty attributes if (!StringUtils.isEmpty(ca.getOwnValue())) { return false; } } } // check attached source relations List<Relation> entSrcRels = ent.getSourceRelations(); List<Relation> cacheSrcRels = relMap.getValuesByBKey(entId); for (Relation rel: entSrcRels) { if (!isRelCurrent(rel)) { return false; } else { if (!cacheSrcRels.remove(rel)) { return false; } } } if (!cacheSrcRels.isEmpty()) { return false; } // check attached target relations List<Relation> entTarRels = ent.getTargetRelations(); List<Relation> cacheTarRels = relMap.getValuesByCKey(entId); for (Relation rel: entTarRels) { if (!isRelCurrent(rel)) { return false; } else { if (!cacheTarRels.remove(rel)) { return false; } } } if (!cacheTarRels.isEmpty()) { return false; } return true; } public class EntityDiff { public List<Attribute> addedAttributes = new ArrayList<Attribute>(); public List<Attribute> removedAttributes = new ArrayList<Attribute>(); public List<Attribute> modifiedAttributes = new ArrayList<Attribute>(); public List<Relation> addedSrcRels = new ArrayList<Relation>(); public List<Relation> removedSrcRels = new ArrayList<Relation>(); public List<Relation> modifiedSrcRels = new ArrayList<Relation>(); public List<Relation> addedTarRels = new ArrayList<Relation>(); public List<Relation> removedTarRels = new ArrayList<Relation>(); public List<Relation> modifiedTarRels = new ArrayList<Relation>(); } /** * Returns an EntityDiff with the differences between the given Entity and the current cache. * * Ignores empty Attributes. Compares only content if acceptNewIDs. * * @param ent * @return * @throws Exception */ public EntityDiff diffEntityCache(Entity ent, boolean acceptNewIDs) throws Exception { if (ent.isLightweight()) { throw new IllegalStateException("Can not diff attributes and relations of lightweight entity!"); } Long entId = ent.getId(); EntityDiff diff = new EntityDiff(); /* * check attributes */ List<Attribute> entAtts = ent.getAttributes(); List<Attribute> cacheAtts = attMap.getValuesByBKey(entId); // check attached attributes and compare to cached for (Attribute att : entAtts) { if (!isAttCurrent(att)) { diff.modifiedAttributes.add(att); } if (!cacheAtts.remove(att)) { boolean found = false; for (Attribute ca : cacheAtts) { if (ca.getId() == att.getId()) { cacheAtts.remove(ca); found = true; break; } else if (acceptNewIDs && ca.equalsContent(att)) { // same content is good enough cacheAtts.remove(ca); found = true; break; } } if (!found) { diff.addedAttributes.add(att); } } } if (!cacheAtts.isEmpty()) { // more cached attributes for (Attribute ca : cacheAtts) { // ignore empty attributes if (!StringUtils.isEmpty(ca.getOwnValue())) { diff.removedAttributes.add(ca); } } } /* * source relations */ List<Relation> entSrcRels = ent.getSourceRelations(); List<Relation> cacheSrcRels = relMap.getValuesByBKey(entId); // check attached source relations and compare to cached for (Relation rel : entSrcRels) { if (!isRelCurrent(rel)) { diff.modifiedSrcRels.add(rel); } if (!cacheSrcRels.remove(rel)) { // rel was not in cache boolean found = false; for (Relation cr : cacheSrcRels) { // check all cached relations if (cr.getId() == rel.getId()) { // relation id is same cacheSrcRels.remove(cr); found = true; break; } else if (acceptNewIDs && cr.equalsContent(rel)) { // same content is good enough // (includes checks for src and tar id) cacheSrcRels.remove(cr); found = true; break; } } if (!found) { diff.addedSrcRels.add(rel); } } } if (!cacheSrcRels.isEmpty()) { for (Relation rel : cacheSrcRels) { diff.removedSrcRels.add(rel); } } /* * target relations */ List<Relation> entTarRels = ent.getTargetRelations(); List<Relation> cacheTarRels = relMap.getValuesByCKey(entId); // check attached target relations and compare to cached for (Relation rel : entTarRels) { if (!isRelCurrent(rel)) { diff.modifiedTarRels.add(rel); } if (!cacheTarRels.remove(rel)) { // rel was not in cache boolean found = false; for (Relation cr : cacheTarRels) { // check all cached relations if (cr.getId() == rel.getId()) { // relation id is same cacheTarRels.remove(cr); found = true; break; } else if (acceptNewIDs && cr.equalsContent(rel)) { // same content is good enough // (includes checks for src and tar id) cacheTarRels.remove(cr); found = true; break; } } if (!found) { diff.addedTarRels.add(rel); } } } if (!cacheTarRels.isEmpty()) { for (Relation rel : cacheTarRels) { diff.removedTarRels.add(rel); } } // return null if diff is empty if (diff.addedAttributes.isEmpty() && diff.removedAttributes.isEmpty() && diff.modifiedAttributes.isEmpty() && diff.addedSrcRels.isEmpty() && diff.removedSrcRels.isEmpty() && diff.modifiedSrcRels.isEmpty() && diff.addedTarRels.isEmpty() && diff.removedTarRels.isEmpty() && diff.modifiedTarRels.isEmpty()) { return null; } return diff; } public List<ViewerAttribute> getViewerAttributes(Long page){ return getViewerAttMap().getValuesByAKey(page); } public Collection<ViewerPage> getViewerPages(){ return getViewerPageMap().values(); } public ViewerPage saveViewerPage(ViewerPage page){ this.getPs().saveViewerPage(page); this.getViewerPageMap().put(page.getId(), page); return page; } public ViewerAttribute saveViewerAttribute(ViewerPage page, ViewerAttribute att) throws Exception{ logger.info("saveViewerAttribute Page[id="+ page.getId() +", label=" + page.getLabel() + "] Att[id="+ att.getId() +", label="+ att.getLabel() +"]"); if(!page.isPersistent()){ throw new Exception("The ViewerPage associated the the current attribute is not persistent."); } att.setPage(page.getId()); this.getPs().saveViewerAttribute(att); this.getViewerAttMap().put(att.getKey(), att); return att; } }