OpenInspectSessionsHandler : handler for opening the inspect session dialog
authorCherian Mathew <c.mathew@bgbm.org>
Thu, 19 Feb 2015 16:42:15 +0000 (16:42 +0000)
committerCherian Mathew <c.mathew@bgbm.org>
Thu, 19 Feb 2015 16:42:15 +0000 (16:42 +0000)
CacheLoader : moved recursive logic from cdm transient cacher to new class
CdmServiceCacher : now uses CacheLoader to recursively load entities
CdmTransientEntityCacher : moved recursive logic from cdm transient cacher to new class  and corrected caching issues
EntityCacherDebugResult : corrected recursion and added getter method for debug output
CdmEntitySessionManager : now sets active session to null when it is disposed
remotingApplicationContext.xml : corrected exclude
AbstractUtility : new utility method to execute handler
InspectSessionsDialog : added debug text info and cosmetic changes
SessionsViewPart : now opens inspect sessions dialog on button push

13 files changed:
.gitattributes
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/cache/CdmServiceCacher.java
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CacheLoader.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CdmTransientEntityCacher.java
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/EntityCacherDebugResult.java
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySession.java
eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java
eu.etaxonomy.taxeditor.cdmlib/src/main/resources/eu/etaxonomy/cdm/remotingApplicationContext.xml
eu.etaxonomy.taxeditor.store/plugin.xml
eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/OpenInspectSessionsHandler.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/AbstractUtility.java
eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/view/sessions/InspectSessionsDialog.java
eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/view/sessions/SessionsViewPart.java

index 37b3d113176cde0fa8a1a15a2bd169c0cefee2fb..01821c8a0aa6f4330fc9132ac3dcfbfe84e24e89 100644 (file)
@@ -333,6 +333,7 @@ eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/Rem
 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/cache/CdmServiceCacher.java -text
 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/CdmEagerLoadingException.java -text
 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/CdmRemotingException.java -text
+eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CacheLoader.java -text
 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CachedCommonServiceImpl.java -text
 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CdmClientCacheException.java -text
 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CdmEntityCacheKey.java -text
@@ -1278,6 +1279,7 @@ eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/Op
 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/SelectFeatureTreeWizard.java -text
 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/SelectFeatureTreeWizardPage.java -text
 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/OpenDistributionEditorWizardHandler.java -text
+eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/OpenInspectSessionsHandler.java -text
 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/OpenPasswordWizzardHandler.java -text
 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/ShowLoginWindowHandler.java -text
 eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/ShowRemotingLoginWindowHandler.java -text
index 78678a82efa7f7c5a7a046888d861acb2f5c7b7d..05cc819def681b5b6c5e1281722ce9e8b2ba9a87 100644 (file)
@@ -7,6 +7,8 @@ import org.springframework.stereotype.Component;
 
 import eu.etaxonomy.cdm.api.service.ITermService;
 import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.common.DefinedTermBase;
+import eu.etaxonomy.taxeditor.remoting.cache.CacheLoader;
 import eu.etaxonomy.taxeditor.remoting.cache.CdmTransientEntityCacher;
 
 /**
@@ -21,20 +23,26 @@ import eu.etaxonomy.taxeditor.remoting.cache.CdmTransientEntityCacher;
  * @param <T>
  */
 @Component
-public class CdmServiceCacher extends CdmCacher {
+public class CdmServiceCacher extends CdmCacher{
 
        @Autowired
        ITermService termService;
 
+       private CacheLoader cacheLoader;
+
        @Override
        protected void setup() {
+           DefinedTermBase.setCacher(this);
                CdmTransientEntityCacher.setDefaultCacher(this);
+               cacheLoader = new CacheLoader(this);
        }
 
        @Override
        protected CdmBase findByUuid(UUID uuid) {
                CdmBase term = termService.findWithoutFlush(uuid);
-               return term;
+               return cacheLoader.load(term, true);
+
        }
 
+
 }
diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CacheLoader.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/cache/CacheLoader.java
new file mode 100644 (file)
index 0000000..cb2879a
--- /dev/null
@@ -0,0 +1,408 @@
+// $Id$
+/**
+ * Copyright (C) 2015 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
+package eu.etaxonomy.taxeditor.remoting.cache;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javassist.util.proxy.ProxyFactory;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+import org.hibernate.collection.spi.PersistentCollection;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.springframework.util.ReflectionUtils;
+
+import eu.etaxonomy.cdm.model.ICdmCacher;
+import eu.etaxonomy.cdm.model.common.CdmBase;
+
+/**
+ * @author cmathew
+ * @date 19 Feb 2015
+ *
+ */
+public class CacheLoader {
+    private static final Logger logger = Logger.getLogger(CacheLoader.class);
+
+    private static boolean isRecursiveEnabled = true;
+
+    private final ICdmCacher cdmCacher;
+
+    private final Cache cdmlibModelCache;
+
+
+    public CacheLoader(ICdmCacher cdmCacher) {
+        this.cdmCacher = cdmCacher;
+        this.cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache();
+    }
+
+
+    public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
+        Element e = cdmlibModelCache.get(className);
+        if (e == null) {
+            return null;
+        } else {
+            return (CdmModelFieldPropertyFromClass) e.getObjectValue();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Object> T load(T obj, boolean recursive) {
+        if(obj == null) {
+            return null;
+        }
+        if(obj instanceof CdmBase) {
+            return (T) load((CdmBase)obj, recursive);
+        } else if (obj instanceof Map) {
+            return (T) load((Map<T,T>)obj, recursive);
+        } else if (obj instanceof Collection) {
+            return (T) load((Collection<T>)obj, recursive);
+        }
+
+        return obj;
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends Object> T loadRecursive(T obj, Set<CdmBase> alreadyVisitedEntities) {
+        if(obj == null) {
+            return null;
+        }
+        if(obj instanceof CdmBase) {
+            return (T) loadRecursive((CdmBase)obj, alreadyVisitedEntities);
+        } else if (obj instanceof Map) {
+            return (T) load((Map<T,T>)obj, alreadyVisitedEntities);
+        } else if (obj instanceof Collection) {
+            return (T) load((Collection<T>)obj, alreadyVisitedEntities);
+        }
+
+
+        logger.info("No caching yet for type " + obj.getClass().getName());
+
+        return obj;
+    }
+
+    public <T extends Object> Map<T,T> load(Map<T,T> map, boolean recursive){
+        if(map == null) {
+            return null;
+        }
+
+        if(isRecursiveEnabled && recursive) {
+            logger.info("---- starting recursive load for cdm entity map");
+            Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
+            Map<T,T> cachedMap = load(map, alreadyVisitedEntities);
+            alreadyVisitedEntities.clear();
+            logger.info("---- ending recursive load for cdm entity map \n");
+            return cachedMap;
+        } else {
+            return load(map, null);
+        }
+    }
+
+
+    private <T extends Object> Map<T,T> load(Map<T,T> map, Set<CdmBase> alreadyVisitedEntities){
+        if(map == null || map.isEmpty()) {
+            return map;
+        }
+
+        int originalMapSize = map.size();
+        Object[] result = new Object[ map.size() * 2 ];
+        Iterator<Map.Entry<T,T>> iter = map.entrySet().iterator();
+        int i=0;
+        while ( iter.hasNext() ) {
+            Map.Entry<T,T> e = iter.next();
+            result[i++] = e.getKey();
+            result[i++] = e.getValue();
+        }
+
+        for(i=0; i<result.length;i++) {
+            if(alreadyVisitedEntities == null) {
+                result[i] = load(result[i], false);
+            } else {
+                result[i] = loadRecursive(result[i], alreadyVisitedEntities);
+            }
+        }
+        map.clear();
+        for(i = 0; i < originalMapSize; i+=2 ) {
+            map.put(
+                    (T)result[i],
+                    (T)result[i+1]
+                    );
+        }
+        return map;
+    }
+
+    public <T extends Object> Collection<T> load(Collection<T> collection, boolean recursive){
+        if(collection == null) {
+            return null;
+        }
+
+        Collection<T> loadedCollection;
+        if(isRecursiveEnabled && recursive) {
+            logger.info("---- starting recursive load for cdm entity collection");
+            Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
+            Collection<T> cachedCollection = load(collection, alreadyVisitedEntities);
+            alreadyVisitedEntities.clear();
+            logger.info("---- ending recursive load for cdm entity collection \n");
+            loadedCollection = cachedCollection;
+        } else {
+            loadedCollection = load(collection, null);
+        }
+        return loadedCollection;
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends Object> Collection<T> load(Collection<T> collection, Set<CdmBase> alreadyVisitedEntities){
+        int length = collection.size();
+        Object[] result = new Object[length];
+        Iterator<T> collectionItr = collection.iterator();
+        int count = 0;
+        while(collectionItr.hasNext()) {
+            Object obj = collectionItr.next();
+            if(alreadyVisitedEntities == null) {
+                result[count] = load(obj, false);
+            } else {
+                result[count] = loadRecursive(obj, alreadyVisitedEntities);
+            }
+
+            count++;
+        }
+
+        collection.clear();
+
+        for ( int i = 0; i < length; i++ ) {
+            collection.add((T)result[i]);
+        }
+
+        return collection;
+    }
+
+
+    /**
+     * Puts the (Key,Value) pair of ({@link java.util.UUID}, {@link eu.etaxonomy.cdm.model.common.CdmBase}),
+     * in the cache corresponding to the given cache id
+     *
+     * @param cacheId
+     * @param uuid
+     * @param cdmEntity
+     */
+    public CdmBase load(CdmBase cdmEntity, boolean recursive) {
+        if(cdmEntity == null) {
+            return null;
+        }
+
+
+        // start by looking up the cdm entity in the cache
+        CdmBase cachedCdmEntity = cdmCacher.getFromCache(cdmEntity);
+
+        if(cachedCdmEntity != null) {
+            // if cdm entity was found in cache then
+            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
+            // .. return if the cached and input objects are identical, else (this is a newly loaded object so) continue
+            if(cachedCdmEntity == cdmEntity) {
+                return cachedCdmEntity;
+            }
+            return cachedCdmEntity;
+        }
+
+        CdmBase loadedCdmBase;
+        if(isRecursiveEnabled && recursive) {
+            logger.info("---- starting recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
+            Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
+            CdmBase cb =  loadRecursive(cdmEntity, alreadyVisitedEntities);
+            alreadyVisitedEntities.clear();
+            logger.info("---- ending recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + "\n");
+            loadedCdmBase =  cb;
+        } else {
+            loadedCdmBase = load(cdmEntity);
+        }
+        return loadedCdmBase;
+
+    }
+
+
+    private CdmBase load(CdmBase cdmEntity) {
+        logger.info("loading object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
+
+        // start by looking up the cdm entity in the cache
+        CdmBase cachedCdmEntity = cdmCacher.getFromCache(cdmEntity);
+
+        if(cachedCdmEntity != null) {
+            // if cdm entity was found in cache then return ...
+            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
+            return cachedCdmEntity;
+        } else {
+            // ... else save the entity in the cache
+            cdmCacher.put(cdmEntity);
+            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache");
+            return cdmEntity;
+        }
+    }
+
+    private CdmBase loadRecursive(CdmBase cdmEntity,  Set<CdmBase> alreadyVisitedEntities) {
+
+        CdmBase cachedCdmEntity = load(cdmEntity);
+
+
+        // we want to recursive through the cdmEntity (and not the cachedCdmEntity)
+        // since there could be new or deleted objects in the cdmEntity sub-graph
+
+        // start by getting the fields from the cdm entity
+        String className = cdmEntity.getClass().getName();
+        CdmModelFieldPropertyFromClass cmgmfc = getFromCdmlibModelCache(className);
+        if(cmgmfc != null) {
+            alreadyVisitedEntities.add(cdmEntity);
+            List<String> fields = cmgmfc.getFields();
+            for(String field : fields) {
+                // retrieve the actual object corresponding to the field.
+                // this object will be either a CdmBase or a Collection / Map
+                // with CdmBase as the generic type
+
+                CdmBase cdmEntityInSubGraph = getCdmBaseTypeFieldValue(cdmEntity, cachedCdmEntity, field, alreadyVisitedEntities);
+                if(cdmEntityInSubGraph != null) {
+                    //checkForIdenticalCdmEntity(alreadyVisitedEntities, cdmEntityInSubGraph);
+                    if(!alreadyVisitedEntities.contains(cdmEntityInSubGraph)) {
+                        logger.info("recursive loading object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId());
+                        loadRecursive(cdmEntityInSubGraph, alreadyVisitedEntities);
+                    } else {
+                        logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited");
+                    }
+
+                }
+            }
+        } else {
+            throw new CdmClientCacheException("CdmEntity with class " + cdmEntity.getClass().getName() + " is not found in the cdmlib model cache. " +
+                    "The cache may be corrupted or not in sync with the latest model version" );
+        }
+        return cachedCdmEntity;
+    }
+
+
+    private CdmBase getCdmBaseTypeFieldValue(CdmBase cdmEntity,
+            CdmBase cachedCdmEntity,
+            String fieldName,
+            Set<CdmBase> alreadyVisitedEntities) {
+
+        // this method attempts to make sure that for any two objects found in
+        // the object graph, if they are equal then they should also be the same,
+        // which is crucial for the merge to work
+        if(cachedCdmEntity == null) {
+            throw new CdmClientCacheException("When trying to set field value, the cached cdm entity cannot be null");
+        }
+
+        Class<?> clazz = cdmEntity.getClass();
+        try {
+            // this call will search in the provided class as well as
+            // the super classes until it finds the field
+            Field field = ReflectionUtils.findField(clazz, fieldName);
+
+            if(field == null) {
+                throw new CdmClientCacheException("Field '" + fieldName
+                        + "' not found when searching in class '" + clazz.getName() + "' and its supercalsses");
+            }
+            field.setAccessible(true);
+            Object o = field.get(cdmEntity);
+
+            if(o != null && o instanceof HibernateProxy) {
+                LazyInitializer hli = ((HibernateProxy)o).getHibernateLazyInitializer();
+                if(!hli.isUninitialized()) {
+                    o = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation();
+                    field.set(cdmEntity, o);
+                }
+            }
+
+            if(o != null && o instanceof PersistentCollection) {
+                PersistentCollection pc = ((PersistentCollection)o);
+                if(pc.wasInitialized()) {
+                    o = ProxyUtils.getObject(pc);
+                    field.set(cdmEntity, o);
+                }
+            }
+
+
+            CdmBase cdmEntityInSubGraph = null;
+            if(o != null
+                    && !ProxyFactory.isProxyClass(o.getClass())
+                    && !(o instanceof PersistentCollection) ) {
+
+                if(CdmBase.class.isAssignableFrom(o.getClass())) {
+                    logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
+                    cdmEntityInSubGraph  = (CdmBase)o;
+
+
+                    CdmBase cachedCdmEntityInSubGraph = cdmCacher.getFromCache(cdmEntityInSubGraph);
+                    // making sure that the field in cached cdm entity is always
+                    // up-to-date by setting to the value of the cdm entity being loaded
+                    // the only execption to this is found below
+                    field.set(cachedCdmEntity, o);
+
+
+                    // the only exception to updating the field to the latest value
+                    // is the case where the field has been already initialised, cached and
+                    // is not the same as the one in the cache, in which case we set the value
+                    // of the field to the one found in the cache
+                    if(cachedCdmEntityInSubGraph != null) {
+                        if(cachedCdmEntityInSubGraph != cdmEntityInSubGraph) {
+                            logger.info("setting cached + real value to '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
+                            field.set(cachedCdmEntity, cachedCdmEntityInSubGraph);
+                            field.set(cdmEntity, cachedCdmEntityInSubGraph);
+                        }
+                        cdmEntityInSubGraph = null;
+                    }
+
+                } else if(o instanceof Map) {
+                    loadRecursive((Map)o, alreadyVisitedEntities);
+                } else if(o instanceof Collection) {
+                    loadRecursive((Collection)o, alreadyVisitedEntities);
+                }
+            }
+            // we return the original cdm entity in the sub graph because we
+            // want to continue to recurse on the input cdm entity graph
+            // and not the one in the cache
+            return cdmEntityInSubGraph;
+        } catch (SecurityException e) {
+            throw new CdmClientCacheException(e);
+        } catch (IllegalArgumentException e) {
+            throw new CdmClientCacheException(e);
+        } catch (IllegalAccessException e) {
+            throw new CdmClientCacheException(e);
+        }
+    }
+
+    private boolean checkForIdenticalCdmEntity(Set<CdmBase> cbSet, CdmBase cbToCompare) {
+        if(cbToCompare != null) {
+            for(CdmBase cb : cbSet) {
+
+                if(cb == cbToCompare) {
+                    return true;
+                } else {
+                    if(cb.equals(cbToCompare)) {
+                        logger.info("equal but non identical object found of type " + cbToCompare.getUserFriendlyTypeName() + " with id " + cbToCompare.getId());
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean isRecursiveEnabled() {
+        return isRecursiveEnabled;
+    }
+
+    public static void  setRecursiveEnabled(boolean ire) {
+        isRecursiveEnabled = ire;
+    }
+}
index a5146bf31e28256fc5a80e85b907a7d675bbd68e..7899e338a22990f571d81cbea65596b08c10b301 100644 (file)
@@ -9,16 +9,11 @@
  */
 package eu.etaxonomy.taxeditor.remoting.cache;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
-import javassist.util.proxy.ProxyFactory;
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.Element;
 import net.sf.ehcache.config.CacheConfiguration;
@@ -27,12 +22,9 @@ import net.sf.ehcache.statistics.LiveCacheStatistics;
 import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
 
 import org.apache.log4j.Logger;
-import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.proxy.HibernateProxy;
-import org.hibernate.proxy.LazyInitializer;
-import org.springframework.util.ReflectionUtils;
 
 import eu.etaxonomy.cdm.api.cache.CdmServiceCacher;
+import eu.etaxonomy.cdm.model.ICdmCacher;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
 
@@ -50,22 +42,22 @@ import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
  *
  */
 
-public class CdmTransientEntityCacher  {
+public class CdmTransientEntityCacher implements ICdmCacher {
 
     private static final Logger logger = Logger.getLogger(CdmTransientEntityCacher.class);
 
 
-    private ICdmEntitySessionManager cdmEntitySessionManager;
+    private final ICdmEntitySessionManager cdmEntitySessionManager;
 
     private static CdmServiceCacher cdmServiceCacher;
 
-    private String cacheId;
+    private final String cacheId;
 
-    private Cache cache;
+    private final Cache cache;
+
+    private final CacheLoader cacheLoader;
 
-    private Cache cdmlibModelCache;
 
-    private static boolean isRecursiveEnabled = true;
 
     public static enum CollectionType {
         SET,
@@ -78,17 +70,14 @@ public class CdmTransientEntityCacher  {
         }
     }
 
-    private CdmTransientEntityCacher() {
-
-    }
 
     public CdmTransientEntityCacher(String cacheId, ICdmEntitySessionManager cdmEntitySessionManager) {
         this.cacheId = cacheId;
 
         cache = new Cache(getEntityCacheConfiguration(cacheId));
-        cdmServiceCacher.getDefaultCacheManager().addCache(cache);
+        CdmRemoteCacheManager.getInstance().getDefaultCacheManager().addCache(cache);
 
-        cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache();
+        cacheLoader = new CacheLoader(this);
         this.cdmEntitySessionManager = cdmEntitySessionManager;
 
 
@@ -137,334 +126,40 @@ public class CdmTransientEntityCacher  {
      * @return
      */
     private Cache getCache() {
-        return cdmServiceCacher.getDefaultCacheManager().getCache(cacheId);
+        return  CdmRemoteCacheManager.getInstance().getDefaultCacheManager().getCache(cacheId);
     }
 
-    @SuppressWarnings("unchecked")
     public <T extends Object> T load(T obj, boolean recursive) {
-        if(obj == null) {
-            return null;
-        }
-        if(obj instanceof CdmBase) {
-            return (T) load((CdmBase)obj, recursive);
-        } else if (obj instanceof Map) {
-            return (T) load((Map<T,T>)obj, recursive);
-        } else if (obj instanceof Collection) {
-            return (T) load((Collection<T>)obj, recursive);
-        }
-
-        return obj;
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T extends Object> T loadRecursive(T obj, Set<CdmBase> alreadyVisitedEntities) {
-        if(obj == null) {
-            return null;
-        }
-        if(obj instanceof CdmBase) {
-            return (T) loadRecursive((CdmBase)obj, alreadyVisitedEntities);
-        } else if (obj instanceof Map) {
-            return (T) load((Map<T,T>)obj, alreadyVisitedEntities);
-        } else if (obj instanceof Collection) {
-            return (T) load((Collection<T>)obj, alreadyVisitedEntities);
-        }
-
-
-        logger.info("No caching yet for type " + obj.getClass().getName());
-
-        return obj;
+        return cacheLoader.load(obj, recursive);
     }
 
     public <T extends Object> Map<T,T> load(Map<T,T> map, boolean recursive){
-        if(map == null) {
-            return null;
-        }
-
-        if(isRecursiveEnabled && recursive) {
-            logger.info("---- starting recursive load for cdm entity map");
-            Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
-            Map<T,T> cachedMap = load(map, alreadyVisitedEntities);
-            alreadyVisitedEntities.clear();
-            logger.info("---- ending recursive load for cdm entity map \n");
-            return cachedMap;
-        } else {
-            return load(map, null);
-        }
-    }
-
-
-    private <T extends Object> Map<T,T> load(Map<T,T> map, Set<CdmBase> alreadyVisitedEntities){
-        if(map == null || map.isEmpty()) {
-            return map;
-        }
-
-        int originalMapSize = map.size();
-        Object[] result = new Object[ map.size() * 2 ];
-        Iterator<Map.Entry<T,T>> iter = map.entrySet().iterator();
-        int i=0;
-        while ( iter.hasNext() ) {
-            Map.Entry<T,T> e = iter.next();
-            result[i++] = e.getKey();
-            result[i++] = e.getValue();
-        }
-
-        for(i=0; i<result.length;i++) {
-            if(alreadyVisitedEntities == null) {
-                result[i] = load(result[i], false);
-            } else {
-                result[i] = loadRecursive(result[i], alreadyVisitedEntities);
-            }
-        }
-        map.clear();
-        for(i = 0; i < originalMapSize; i+=2 ) {
-            map.put(
-                    (T)result[i],
-                    (T)result[i+1]
-                    );
-        }
-        return map;
+        return cacheLoader.load(map, recursive);
     }
 
     public <T extends Object> Collection<T> load(Collection<T> collection, boolean recursive){
-        if(collection == null) {
-            return null;
-        }
-
-        Collection<T> loadedCollection;
-        if(isRecursiveEnabled && recursive) {
-            logger.info("---- starting recursive load for cdm entity collection");
-            Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
-            Collection<T> cachedCollection = load(collection, alreadyVisitedEntities);
-            alreadyVisitedEntities.clear();
-            logger.info("---- ending recursive load for cdm entity collection \n");
-            loadedCollection = cachedCollection;
-        } else {
-            loadedCollection = load(collection, null);
-        }
-        return loadedCollection;
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T extends Object> Collection<T> load(Collection<T> collection, Set<CdmBase> alreadyVisitedEntities){
-        int length = collection.size();
-        Object[] result = new Object[length];
-        Iterator<T> collectionItr = collection.iterator();
-        int count = 0;
-        while(collectionItr.hasNext()) {
-            Object obj = collectionItr.next();
-            if(alreadyVisitedEntities == null) {
-                result[count] = load(obj, false);
-            } else {
-                result[count] = loadRecursive(obj, alreadyVisitedEntities);
-            }
-
-            count++;
-        }
-
-        collection.clear();
-
-        for ( int i = 0; i < length; i++ ) {
-            collection.add((T)result[i]);
-        }
-
-        return collection;
+        return cacheLoader.load(collection, recursive);
     }
 
-
-    /**
-     * Puts the (Key,Value) pair of ({@link java.util.UUID}, {@link eu.etaxonomy.cdm.model.common.CdmBase}),
-     * in the cache corresponding to the given cache id
-     *
-     * @param cacheId
-     * @param uuid
-     * @param cdmEntity
-     */
     public CdmBase load(CdmBase cdmEntity, boolean recursive) {
-        if(cdmEntity == null) {
-            return null;
-        }
-
-
-        // start by looking up the cdm entity in the cache
-        CdmBase cachedCdmEntity = getFromCache(cdmEntity);
-
-        if(cachedCdmEntity != null) {
-            // if cdm entity was found in cache then
-            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
-            // .. return if the cached and input objects are identical, else (this is a newly loaded object so) continue
-            if(cachedCdmEntity == cdmEntity) {
-                return cachedCdmEntity;
-            }
-        }
-
-        CdmBase loadedCdmBase;
-        if(isRecursiveEnabled && recursive) {
-            logger.info("---- starting recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
-            Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
-            CdmBase cb =  loadRecursive(cdmEntity, alreadyVisitedEntities);
-            alreadyVisitedEntities.clear();
-            logger.info("---- ending recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + "\n");
-            loadedCdmBase =  cb;
-        } else {
-            loadedCdmBase = load(cdmEntity);
-        }
-        return loadedCdmBase;
-
-    }
-
-
-    private CdmBase load(CdmBase cdmEntity) {
-        logger.info("loading object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
-
-        // start by looking up the cdm entity in the cache
-        CdmBase cachedCdmEntity = getFromCache(cdmEntity);
-
-        if(cachedCdmEntity != null) {
-            // if cdm entity was found in cache then return ...
-            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
-            return cachedCdmEntity;
-        } else {
-            // ... else save the entity in the cache
-            getCache().put(new Element(generateKey(cdmEntity), cdmEntity));
-            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache");
-            return cdmEntity;
-        }
+        return cacheLoader.load(cdmEntity, recursive);
     }
 
-    private CdmBase loadRecursive(CdmBase cdmEntity, Set<CdmBase> alreadyVisitedEntities) {
-
-        CdmBase cachedCdmEntity = load(cdmEntity);
-
-        // we want to recursive through the cdmEntity (and not the cachedCdmEntity)
-        // since there could be new or deleted objects in the cdmEntity sub-graph
-
-        // start by getting the fields from the cdm entity
-        String className = cdmEntity.getClass().getName();
-        CdmModelFieldPropertyFromClass cmgmfc = getFromCdmlibModelCache(className);
-        if(cmgmfc != null) {
-            alreadyVisitedEntities.add(cdmEntity);
-            List<String> fields = cmgmfc.getFields();
-            for(String field : fields) {
-                // retrieve the actual object corresponding to the field.
-                // this object will be either a CdmBase or a Collection / Map
-                // with CdmBase as the generic type
-
-                CdmBase cdmEntityInSubGraph = getCdmBaseTypeFieldValue(cdmEntity, cachedCdmEntity, field, alreadyVisitedEntities);
-                if(cdmEntityInSubGraph != null) {
-                    if(!alreadyVisitedEntities.contains(cdmEntityInSubGraph)) {
-                        logger.info("recursive loading object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId());
-                        loadRecursive(cdmEntityInSubGraph, alreadyVisitedEntities);
-                    } else {
-                        logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited");
-                    }
-                }
-            }
-        } else {
-            throw new CdmClientCacheException("CdmEntity with class " + cdmEntity.getClass().getName() + " is not found in the cdmlib model cache. " +
-                    "The cache may be corrupted or not in sync with the latest model version" );
-        }
-        return cachedCdmEntity;
+    public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
+        return cacheLoader.getFromCdmlibModelCache(className);
     }
 
 
-    private CdmBase getCdmBaseTypeFieldValue(CdmBase cdmEntity,
-            CdmBase cachedCdmEntity,
-            String fieldName,
-            Set<CdmBase> alreadyVisitedEntities) {
-
-        // this method attempts to make sure that for any two objects found in
-        // the object graph, if they are equal then they should also be the same,
-        // which is crucial for the merge to work
-        if(cachedCdmEntity == null) {
-            throw new CdmClientCacheException("When trying to set field value, the cached cdm entity cannot be null");
-        }
-
-        Class<?> clazz = cdmEntity.getClass();
-        try {
-            // this call will search in the provided class as well as
-            // the super classes until it finds the field
-            Field field = ReflectionUtils.findField(clazz, fieldName);
-
-            if(field == null) {
-                throw new CdmClientCacheException("Field '" + fieldName
-                        + "' not found when searching in class '" + clazz.getName() + "' and its supercalsses");
-            }
-            field.setAccessible(true);
-            Object o = field.get(cdmEntity);
-
-            if(o != null && o instanceof HibernateProxy) {
-                LazyInitializer hli = ((HibernateProxy)o).getHibernateLazyInitializer();
-                if(!hli.isUninitialized()) {
-                    o = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation();
-                    field.set(cdmEntity, o);
-                }
-            }
-
-            if(o != null && o instanceof PersistentCollection) {
-                PersistentCollection pc = ((PersistentCollection)o);
-                if(pc.wasInitialized()) {
-                    o = ProxyUtils.getObject(pc);
-                    field.set(cdmEntity, o);
-                }
-            }
-
-            //field.set(cdmEntity, o);
-            CdmBase cdmEntityInSubGraph = null;
-            if(o != null
-                    && !ProxyFactory.isProxyClass(o.getClass())
-                    && !(o instanceof PersistentCollection)    ) {
-
-                if(CdmBase.class.isAssignableFrom(o.getClass())) {
-                    logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
-                    cdmEntityInSubGraph  = (CdmBase)o;
-                    CdmBase cachedCdmEntityInSubGraph = getFromCache(cdmEntityInSubGraph);
-                    // making sure that the field in cached cdm entity is always
-                    // up-to-date by setting to the value of the cdm entity being loaded
-                    // the only execption to this is found below
-                    field.set(cachedCdmEntity, o);
-
-                    // the only exception to updating the field to the latest value
-                    // is the case where the field has been already initialised, cached and
-                    // is not the same as the one in the cache, in which case we set the value
-                    // of the field to the one found in the cache
-                    if(cachedCdmEntityInSubGraph != null) {
-                        if(cachedCdmEntityInSubGraph != cdmEntityInSubGraph) {
-                            logger.info("setting cached + real value to '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
-                            field.set(cachedCdmEntity, cachedCdmEntityInSubGraph);
-                        }
-                    }
-                } else if(o instanceof Map) {
-                    loadRecursive((Map)o, alreadyVisitedEntities);
-                } else if(o instanceof Collection) {
-                    loadRecursive((Collection)o, alreadyVisitedEntities);
-                }
-            }
-            // we return the original cdm entity in the sub graph because we
-            // want to continue to recurse on the input cdm entity graph
-            // and not the one in the cache
-            return cdmEntityInSubGraph;
-        } catch (SecurityException e) {
-            throw new CdmClientCacheException(e);
-        } catch (IllegalArgumentException e) {
-            throw new CdmClientCacheException(e);
-        } catch (IllegalAccessException e) {
-            throw new CdmClientCacheException(e);
-        }
-    }
 
 
+    @Override
     public void put(CdmBase cdmEntity) {
         CdmEntityCacheKey id = new CdmEntityCacheKey(cdmEntity);
-        Element cachedCdmEntityElement = getCacheElement(id);
-
-        if(cachedCdmEntityElement == null) {
-            cachedCdmEntityElement = cdmServiceCacher.getCacheElement(cdmEntity.getUuid());
-            if(cachedCdmEntityElement != null) {
-                logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
-                return;
-            }
+        Element cachedCdmEntityElement = cdmServiceCacher.getCacheElement(cdmEntity.getUuid());
+        if(cachedCdmEntityElement != null) {
+            logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
+            return;
         }
-
         getCache().put(new Element(id, cdmEntity));
     }
 
@@ -473,14 +168,6 @@ public class CdmTransientEntityCacher  {
         return getCache().get(key);
     }
 
-    public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
-        Element e = cdmlibModelCache.get(className);
-        if (e == null) {
-            return null;
-        } else {
-            return (CdmModelFieldPropertyFromClass) e.getObjectValue();
-        }
-    }
 
     public CdmBase getFromCache(CdmEntityCacheKey id) {
         Element e = getCacheElement(id);
@@ -496,6 +183,7 @@ public class CdmTransientEntityCacher  {
         return getFromCache(cacheId);
     }
 
+    @Override
     public CdmBase getFromCache(CdmBase cdmBase) {
 
         CdmEntityCacheKey cacheId = generateKey(cdmBase);
@@ -540,7 +228,7 @@ public class CdmTransientEntityCacher  {
     public void dispose() {
         cache.removeAll();
         cache.flush();
-        cdmServiceCacher.getDefaultCacheManager().removeCache(cacheId);
+        CdmRemoteCacheManager.getInstance().getDefaultCacheManager().removeCache(cacheId);
     }
 
 
@@ -555,14 +243,6 @@ public class CdmTransientEntityCacher  {
         return new CdmEntityCacheKey(entityClass, id);
     }
 
-    public static boolean isRecursiveEnabled() {
-        return isRecursiveEnabled;
-    }
-
-    public static void  setRecursiveEnabled(boolean ire) {
-        isRecursiveEnabled = ire;
-    }
-
 
 
 }
index 8e4254a4d28a4fd997289eb1762bc25d01be261a..a5e7ca6334482b235f0e7dca0f97093a4f2023c6 100644 (file)
@@ -13,12 +13,11 @@ import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.IdentityHashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-
-import javassist.util.proxy.ProxyFactory;
+import java.util.Set;
 
 import org.apache.log4j.Logger;
 import org.hibernate.collection.spi.PersistentCollection;
@@ -45,6 +44,8 @@ public class EntityCacherDebugResult {
 
     private List<CdmEntityInfo> rootElements;
 
+    StringBuilder debugOutput = new StringBuilder();
+
     public EntityCacherDebugResult() {
     }
 
@@ -52,10 +53,13 @@ public class EntityCacherDebugResult {
     public <T extends CdmBase> EntityCacherDebugResult(CdmTransientEntityCacher cacher, List<T> rootEntities) {
         this.cacher = cacher;
         init();
+
         if(rootEntities != null && !rootEntities.isEmpty()) {
             for(CdmBase rootEntity : rootEntities) {
                 debug(rootEntity, true);
-                print();
+                String out = toString(duplicateCdmEntityMap, notInCacheList, rootEntity);
+                System.out.println(out);
+                debugOutput.append(out);
                 clear();
             }
 
@@ -85,14 +89,27 @@ public class EntityCacherDebugResult {
         return rootElements;
     }
 
-    private void print() {
-        System.out.println(toString());
+    private void print(Map<CdmEntityInfo, CdmEntityInfo> duplicateCdmEntityMap,
+            List<CdmEntityInfo> notInCacheList,
+            CdmBase rootEntity) {
+        System.out.println(toString(duplicateCdmEntityMap, notInCacheList, rootEntity));
     }
 
 
     @Override
     public String toString() {
+        return debugOutput.toString();
+    }
+
+    private String toString(Map<CdmEntityInfo, CdmEntityInfo> duplicateCdmEntityMap,
+            List<CdmEntityInfo> notInCacheList,
+            CdmBase rootEntity) {
+
+
         StringBuilder sb = new StringBuilder();
+        sb.append(System.getProperty("line.separator"));
+        sb.append("<<< Root Entity " + rootEntity.getUserFriendlyTypeName() + " with id " + rootEntity.getId() + " >>>");
+        sb.append(System.getProperty("line.separator"));
         if(duplicateCdmEntityMap.isEmpty()) {
             sb.append("No Duplicate CDM Entities.");
         } else {
@@ -103,19 +120,19 @@ public class EntityCacherDebugResult {
                 sb.append(System.getProperty("line.separator"));
                 CdmEntityInfo cei = entry.getKey();
                 CdmBase cb = (CdmBase) cei.getObject();
-                CdmBase cbParent = (CdmBase) cei.getParent().getObject();
+                Object cbParent = cei.getParent().getObject();
 
                 CdmEntityInfo dupCei = entry.getValue();
                 CdmBase dupCb = (CdmBase) dupCei.getObject();
-                CdmBase dupCbParent = (CdmBase) dupCei.getParent().getObject();
+                Object dupCbParent = dupCei.getParent().getObject();
 
                 sb.append(" - entity : " + cb.getUserFriendlyTypeName() + "/" + cb.getId() +
-                        " as field " + cei.getField().getName() +
-                        " of entity " + cbParent.getUserFriendlyTypeName() + "/" + cbParent.getId());
+                        " as member " + cei.getField().getName() +
+                        " of entity " + cbParent.getClass().getCanonicalName());
                 sb.append(System.getProperty("line.separator"));
                 sb.append(" - duplicate entity : " + dupCb.getUserFriendlyTypeName() + "/" + dupCb.getId() +
                         " as field " + dupCei.getField().getName() +
-                        " of entity " + dupCbParent.getUserFriendlyTypeName() + "/" + dupCbParent.getId());
+                        " of entity " + dupCbParent.getClass().getCanonicalName());
                 sb.append(System.getProperty("line.separator"));
                 sb.append("-----------");
             }
@@ -131,16 +148,16 @@ public class EntityCacherDebugResult {
 
             for(CdmEntityInfo cei : notInCacheList) {
                 CdmBase cb = (CdmBase) cei.getObject();
-                CdmBase cbParent = (CdmBase) cei.getParent().getObject();
+                Object cbParent = cei.getParent().getObject();
 
                 sb.append(System.getProperty("line.separator"));
 
                 sb.append(" - entity : " + cb.getUserFriendlyTypeName() + "/" + cb.getId() +
                         " as field " + cei.getField().getName() +
-                        " of entity" + cbParent.getUserFriendlyTypeName() + "/" + cbParent.getId());
+                        " of entity" + cbParent.getClass().getCanonicalName());
             }
         }
-
+        sb.append(System.getProperty("line.separator"));
         return sb.toString();
     }
 
@@ -150,7 +167,7 @@ public class EntityCacherDebugResult {
             return;
         }
         logger.info("---- starting recursive debug for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
-        IdentityHashMap<Object, CdmEntityInfo> alreadyVisitedEntities = new IdentityHashMap<Object, CdmEntityInfo>();
+        Set<CdmEntityInfo> alreadyVisitedEntities = new HashSet<CdmEntityInfo>();
         CdmEntityInfo cei = new CdmEntityInfo(cdmEntity);
         debugRecursive(cdmEntity, alreadyVisitedEntities, cei);
         rootElements.add(cei);
@@ -159,7 +176,7 @@ public class EntityCacherDebugResult {
     }
 
     private <T extends Object> void debugRecursive(T obj,
-            IdentityHashMap<Object, CdmEntityInfo> alreadyVisitedEntities,
+            Set<CdmEntityInfo> alreadyVisitedEntities,
             CdmEntityInfo cei) {
         if(obj == null) {
             return;
@@ -167,7 +184,7 @@ public class EntityCacherDebugResult {
         if(obj instanceof CdmBase) {
             debugRecursive((CdmBase)obj, alreadyVisitedEntities, cei);
         } else if (obj instanceof Map) {
-           debug((Map<T,T>)obj, alreadyVisitedEntities, cei);
+            debug((Map<T,T>)obj, alreadyVisitedEntities, cei);
         } else if (obj instanceof Collection) {
             debug((Collection<T>)obj, alreadyVisitedEntities, cei);
         }
@@ -178,7 +195,7 @@ public class EntityCacherDebugResult {
     }
 
     private <T extends Object> void debug(Map<T,T> map,
-            IdentityHashMap<Object, CdmEntityInfo> alreadyVisitedEntities,
+            Set<CdmEntityInfo> alreadyVisitedEntities,
             CdmEntityInfo cei) {
         if(map == null || map.isEmpty()) {
             return;
@@ -198,7 +215,7 @@ public class EntityCacherDebugResult {
     }
 
     private <T extends Object> void debug(Collection<T> collection,
-            IdentityHashMap<Object, CdmEntityInfo> alreadyVisitedEntities,
+            Set<CdmEntityInfo> alreadyVisitedEntities,
             CdmEntityInfo cei) {
         int length = collection.size();
         Object[] result = new Object[length];
@@ -215,9 +232,10 @@ public class EntityCacherDebugResult {
     }
 
     private void debugRecursive(CdmBase cdmEntity,
-            IdentityHashMap<Object, CdmEntityInfo> alreadyVisitedEntities,
+            Set<CdmEntityInfo> alreadyVisitedEntities,
             CdmEntityInfo cei) {
 
+
         // we want to recursive through the cdmEntity (and not the cachedCdmEntity)
         // since there could be new or deleted objects in the cdmEntity sub-graph
 
@@ -225,7 +243,7 @@ public class EntityCacherDebugResult {
         String className = cdmEntity.getClass().getName();
         CdmModelFieldPropertyFromClass cmgmfc = cacher.getFromCdmlibModelCache(className);
         if(cmgmfc != null) {
-            alreadyVisitedEntities.put(cdmEntity, cei);
+            alreadyVisitedEntities.add(cei);
             List<String> fields = cmgmfc.getFields();
             for(String field : fields) {
                 // retrieve the actual object corresponding to the field.
@@ -233,13 +251,16 @@ public class EntityCacherDebugResult {
                 // with CdmBase as the generic type
 
                 CdmEntityInfo childCei = getDebugCdmBaseTypeFieldValue(cdmEntity, field, alreadyVisitedEntities, cei);
-                CdmBase cdmEntityInSubGraph = (CdmBase)childCei.getObject();
-                if(cdmEntityInSubGraph != null) {
-                    if(!alreadyVisitedEntities.keySet().contains(cdmEntityInSubGraph)) {
-                        logger.info("recursive debugging object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId());
-                        debugRecursive(cdmEntityInSubGraph, alreadyVisitedEntities, childCei);
-                    } else {
-                        logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited");
+                if(!childCei.isProxy()) {
+                    Object object = childCei.getObject();
+                    if(object != null && object instanceof CdmBase) {
+                        CdmBase cdmEntityInSubGraph = (CdmBase)object;
+                        if(!containsIdenticalCdmEntity(alreadyVisitedEntities, cdmEntityInSubGraph)) {
+                            logger.info("recursive debugging object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId());
+                            debugRecursive(cdmEntityInSubGraph, alreadyVisitedEntities, childCei);
+                        } else {
+                            logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited");
+                        }
                     }
                 }
             }
@@ -253,7 +274,7 @@ public class EntityCacherDebugResult {
 
     private CdmEntityInfo getDebugCdmBaseTypeFieldValue(CdmBase cdmEntity,
             String fieldName,
-            IdentityHashMap<Object, CdmEntityInfo> alreadyVisitedEntities,
+            Set<CdmEntityInfo> alreadyVisitedEntities,
             CdmEntityInfo cei) {
 
         CdmEntityInfo childCei = null;
@@ -269,11 +290,24 @@ public class EntityCacherDebugResult {
             }
             field.setAccessible(true);
             Object o = field.get(cdmEntity);
+
+            CdmBase cdmEntityInSubGraph = null;
+
+            boolean isHibernateProxy = false;
+            boolean isPersistentCollection = false;
+
+            childCei = new CdmEntityInfo(o);
+            cei.addChild(childCei);
+            childCei.setField(field);
+
             if(o != null) {
+
                 if(o instanceof HibernateProxy) {
                     LazyInitializer hli = ((HibernateProxy)o).getHibernateLazyInitializer();
                     if(!hli.isUninitialized()) {
                         o = hli.getImplementation();
+                    } else {
+                        isHibernateProxy = true;
                     }
                 }
 
@@ -281,47 +315,47 @@ public class EntityCacherDebugResult {
                     PersistentCollection pc = ((PersistentCollection)o);
                     if(pc.wasInitialized()) {
                         o = ProxyUtils.getObject(pc);
+                    } else {
+                        isPersistentCollection = true;
                     }
                 }
-            }
-            childCei = new CdmEntityInfo(o);
-            cei.addChild(childCei);
-            childCei.setField(field);
-            CdmBase cdmEntityInSubGraph = null;
-            if(o != null
-                    && !ProxyFactory.isProxyClass(o.getClass())
-                    && !(o instanceof PersistentCollection) ) {
+                childCei.setObject(o);
+                childCei.setProxy(isHibernateProxy || isPersistentCollection);
+                if(!isHibernateProxy && !isPersistentCollection) {
 
-                if(CdmBase.class.isAssignableFrom(o.getClass())) {
-                    logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
-                    cdmEntityInSubGraph  = (CdmBase)o;
+                    if(CdmBase.class.isAssignableFrom(o.getClass())) {
+                        logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
+                        cdmEntityInSubGraph  = (CdmBase)o;
 
-                    if(alreadyVisitedEntities.keySet().contains(cdmEntityInSubGraph)) {
                         //logger.info("  - found duplicate entity at " + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
-                        CdmEntityInfo dupCei = alreadyVisitedEntities.get(cdmEntityInSubGraph);
-                        addDuplicateEntity(childCei, dupCei);
+                        CdmEntityInfo dupCei = getDuplicate(alreadyVisitedEntities, cdmEntityInSubGraph);
+                        if(dupCei != null) {
+                            addDuplicateEntity(childCei, dupCei);
+                        }
+
+                        CdmBase cachedCdmEntityInSubGraph = cacher.getFromCache(cdmEntityInSubGraph);
+                        // the only exception to updating the field to the latest value
+                        // is the case where the field has been already initialised, cached and
+                        // is not the same as the one in the cache, in which case we set the value
+                        // of the field to the one found in the cache
+                        if(cachedCdmEntityInSubGraph == null) {
+                            // found a cdm entity which is not in cache - need to record this
+                            //logger.info("  - found entity not in cache " + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
+                            addEntityNotInCache(childCei);
+                        }
+
+                    } else if(o instanceof Map) {
+                        debugRecursive((Map)o, alreadyVisitedEntities, childCei);
+                    } else if(o instanceof Collection) {
+                        debugRecursive((Collection)o, alreadyVisitedEntities, childCei);
                     }
 
-
-                    CdmBase cachedCdmEntityInSubGraph = cacher.getFromCache(cdmEntityInSubGraph);
-                    // the only exception to updating the field to the latest value
-                    // is the case where the field has been already initialised, cached and
-                    // is not the same as the one in the cache, in which case we set the value
-                    // of the field to the one found in the cache
-                    if(cachedCdmEntityInSubGraph == null) {
-                        // found a cdm entity which is not in cache - need to record this
-                        //logger.info("  - found entity not in cache " + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
-                        addEntityNotInCache(childCei);
-                    }
-                } else if(o instanceof Map) {
-                    debugRecursive((Map)o, alreadyVisitedEntities, childCei);
-                } else if(o instanceof Collection) {
-                    debugRecursive((Collection)o, alreadyVisitedEntities, childCei);
                 }
             }
             // we return the original cdm entity in the sub graph because we
             // want to continue to recurse on the input cdm entity graph
             // and not the one in the cache
+
             return childCei;
         } catch (SecurityException e) {
             throw new CdmClientCacheException(e);
@@ -333,18 +367,40 @@ public class EntityCacherDebugResult {
     }
 
 
+    private CdmEntityInfo getDuplicate(Set<CdmEntityInfo> alreadyVisitedEntities, Object objectToCompare) {
+        if(objectToCompare != null) {
+            for(CdmEntityInfo cei: alreadyVisitedEntities) {
+                if(objectToCompare.equals(cei.getObject()) && objectToCompare != cei.getObject()) {
+                    return cei;
+                }
+            }
+        }
+        return null;
+    }
 
+    private boolean containsIdenticalCdmEntity(Set<CdmEntityInfo> ceiSet, Object objectToCompare) {
+        if(objectToCompare != null) {
+            for(CdmEntityInfo cei : ceiSet) {
+                if(cei.getObject() == objectToCompare) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 
     public class CdmEntityInfo {
 
-        private final Object object;
+        private Object object;
         private CdmEntityInfo parent;
         private List<CdmEntityInfo> children;
         private Field field;
         private String label;
+        private boolean isProxy;
 
         public CdmEntityInfo(Object object) {
             this.object = object;
+            isProxy = false;
             children = new ArrayList<CdmEntityInfo>();
         }
 
@@ -401,13 +457,13 @@ public class EntityCacherDebugResult {
                     }
                 } else if(object instanceof Collection) {
                     String className = object.getClass().getName();
-                    label = "[" + className + "] " + fieldName + String.valueOf(((Collection)object).size());
+                    label = "[" + className + "] " + fieldName + " : " + String.valueOf(((Collection)object).size());
                 } else if(object instanceof Map) {
                     String className = object.getClass().getName();
-                    label = "[" + className + "] " + fieldName + String.valueOf(((Map)object).size());
+                    label = "[" + className + "] " + fieldName + " : " + String.valueOf(((Map)object).size());
                 } else {
                     String className = object.getClass().getName();
-                    label = "[" + className + "] " + fieldName;
+                    label = "[" + className + "] " + fieldName + " : " + object.toString();
                 }
             } else {
                 label = "[NULL] " + fieldName;
@@ -423,6 +479,18 @@ public class EntityCacherDebugResult {
             return object;
         }
 
+        public void setObject(Object object) {
+            this.object = object;
+        }
+
+        public boolean isProxy() {
+            return isProxy;
+        }
+
+        public void setProxy(boolean isProxy) {
+            this.isProxy = isProxy;
+        }
+
 
 
     }
index c7935d6090629a5315166f40d417b2d923c2c640..a135b63a8e423928b1f88aecaa4388ece4a81639 100644 (file)
@@ -260,7 +260,7 @@ public class CdmEntitySession implements ICdmEntitySession  {
      */
     @Override
     public <T extends CdmBase> T remoteUpdate(IService<T> service, T cdmBase) {
-        debug(cdmBase);
+        //debug(cdmBase);
         T mergedCdmBase = service.merge(cdmBase);
         //cdmTransientEntityCacher.clear();
         // FIXME:Remoting not really sure if we need to reload the new
index 67ad8de81687ccf906ad1483f448b7b8c2b0d643..62f44f22a526898eb48d474711b2ea6cc7cf55c0 100644 (file)
@@ -133,6 +133,9 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager {
                        logger.info("No Session connected to owner, nothing to dispose");
                        return;
                }
+               if(session == activeSession) {
+                   activeSession = null;
+               }
                ownerSessionMap.remove(owner);
                notifyObservers();
        }
index b3cb71f03c3d4939c0c09f2ba5c8906447cc59b9..72d191a56fe380f9716a54f0a3847a2b5cf5d816 100644 (file)
@@ -24,7 +24,7 @@
        <context:component-scan base-package="eu.etaxonomy.cdm.api.cache">\r
                <!-- FIXME:Remoting Temp workaround to make remoting work -->\r
                <context:exclude-filter type="regex"\r
-                       expression="eu\.etaxonomy\.cdm\.api\.cache\.CdmDaoCacher" />\r
+                       expression="eu\.etaxonomy\.cdm\.api\.cache\.CdmTermCacher" />\r
        </context:component-scan>\r
 \r
        <context:component-scan base-package="eu.etaxonomy.taxeditor.remoting.cache"/>\r
index 1e3cb22a7ed6c637f0ececfbf3db21774357f0c5..68fced6cbab7ebd2f3c06bd3bb55279560fb76a1 100644 (file)
             id="eu.etaxonomy.taxeditor.datasource.connect"
             name="Connect">
       </command>
+      <command
+            defaultHandler="eu.etaxonomy.taxeditor.handler.OpenInspectSessionsHandler"
+            id="eu.etaxonomy.taxeditor.store.open.InspectSessionsDialog"
+            name="Inspect Active Session">
+      </command>
    </extension>
    <extension
          point="org.eclipse.ui.importWizards">
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/OpenInspectSessionsHandler.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/handler/OpenInspectSessionsHandler.java
new file mode 100644 (file)
index 0000000..b8af099
--- /dev/null
@@ -0,0 +1,62 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.handler;
+
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.swt.SWT;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.view.sessions.InspectSessionsDialog;
+
+/**
+ * @author cmathew
+ * @date 18 Feb 2015
+ *
+ */
+public class OpenInspectSessionsHandler extends AbstractHandler implements IHandler {
+
+
+    /* (non-Javadoc)
+     * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+     */
+    /** {@inheritDoc} */
+    @Override
+    public Object execute(ExecutionEvent event) throws ExecutionException {
+
+        Object principal = CdmStore.getCurrentAuthentiation().getPrincipal();
+
+        ICdmEntitySession activeSession = CdmStore.getCurrentSessionManager().getActiveSession();
+
+        if(activeSession == null) {
+            MessagingUtils.warningDialog("No Active Session", this, "Active Session is null");
+        } else {
+            List<CdmBase> rootEntities = activeSession.getRootEntities();
+            if(rootEntities == null || rootEntities.isEmpty()) {
+                MessagingUtils.warningDialog("No Root Entities", this, "No root entities to inspect");
+            } else {
+                InspectSessionsDialog dialog = new InspectSessionsDialog(AbstractUtility.getShell(), SWT.NONE);
+                dialog.open();
+            }
+
+        }
+
+        return null;
+
+    }
+}
index 2d21f05c071faad720ffdee9321fe36bda723f15..72d73f88278ae621195ab7a1cf121dbb3fde396f 100644 (file)
@@ -18,6 +18,9 @@ import java.util.List;
 import java.util.TreeSet;
 
 import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.common.NotDefinedException;
 import org.eclipse.core.commands.operations.IOperationHistory;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -44,6 +47,7 @@ import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerService;
 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
 import org.eclipse.ui.part.EditorPart;
 import org.eclipse.ui.progress.IProgressService;
@@ -776,4 +780,28 @@ public abstract class AbstractUtility {
     }
 
 
+    public static void executeCommand(String commandId, Object source, String pluginId) {
+        IHandlerService handlerService = (IHandlerService) AbstractUtility.getService(IHandlerService.class);
+        Exception exception = null;
+        try {
+            handlerService.executeCommand(commandId, null);
+        } catch (ExecutionException e) {
+            exception = e;
+        } catch (NotDefinedException e) {
+            exception = e;
+        } catch (NotEnabledException e) {
+            exception = e;
+        } catch (NotHandledException e) {
+            exception = e;
+        } finally {
+            if(exception != null) {
+                MessagingUtils.errorDialog("Error executing command",
+                        source,
+                        "Could not execute command with id " + commandId ,
+                        pluginId,
+                        exception,
+                        true);
+            }
+        }
+    }
 }
index 3206427e6e0fa66162be4b786c9fcdbbaf823c13..82db7c539083a2a6d45bffcd11bee736002f9c3f 100644 (file)
@@ -21,8 +21,13 @@ import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerCell;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Dialog;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
@@ -47,7 +52,7 @@ public class InspectSessionsDialog extends Dialog {
 
     protected Object result;
     protected Shell shlInspectSessions;
-    private Text text;
+    private Text txtDebugInfo;
     private Label lblDebugInformation;
 
     private final Cache cdmlibModelCache;
@@ -55,6 +60,10 @@ public class InspectSessionsDialog extends Dialog {
     private final ICdmEntitySession activeSession;
 
     private TreeViewer treeViewer;
+    private Button btnClose;
+    EntityCacherDebugResult ecdr;
+    private SashForm sashForm;
+    private Composite compositeDebug;
     /**
      * Create the dialog.
      * @param parent
@@ -62,9 +71,10 @@ public class InspectSessionsDialog extends Dialog {
      */
     public InspectSessionsDialog(Shell parent, int style) {
         super(parent, style);
-        setText("SWT Dialog");
+        setText("Inspect Active Session");
         cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache();
         activeSession = CdmStore.getCurrentSessionManager().getActiveSession();
+        ecdr = activeSession.debug();
     }
 
     /**
@@ -72,7 +82,9 @@ public class InspectSessionsDialog extends Dialog {
      * @return the result
      */
     public Object open() {
+
         createContents();
+        setDebugInfoText();
         treeViewer.setContentProvider(new SessionsTreeContentProvider());
         treeViewer.setLabelProvider(new SessionsTreeLabelProvider());
         treeViewer.setInput(getRootElements());
@@ -91,27 +103,51 @@ public class InspectSessionsDialog extends Dialog {
      * Create contents of the dialog.
      */
     private void createContents() {
-        shlInspectSessions = new Shell(getParent(), getStyle());
-        shlInspectSessions.setSize(641, 529);
+        shlInspectSessions = new Shell(getParent(), SWT.DIALOG_TRIM | SWT.RESIZE);
+        shlInspectSessions.setSize(641, 631);
         shlInspectSessions.setText("Inspect Sessions");
         shlInspectSessions.setLayout(new GridLayout(1, false));
 
-        TreeViewer treeViewer = new TreeViewer(shlInspectSessions, SWT.BORDER);
-        Tree tree = treeViewer.getTree();
-        tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+        sashForm = new SashForm(shlInspectSessions, SWT.VERTICAL);
+        sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+
+                treeViewer = new TreeViewer(sashForm, SWT.BORDER);
+                Tree tree = treeViewer.getTree();
 
-        lblDebugInformation = new Label(shlInspectSessions, SWT.NONE);
-        lblDebugInformation.setFont(SWTResourceManager.getFont("Ubuntu", 10, SWT.NORMAL));
-        lblDebugInformation.setText("Debug Information :");
+                                compositeDebug = new Composite(sashForm, SWT.NONE);
+                                                        compositeDebug.setLayout(new GridLayout(1, false));
 
-        text = new Text(shlInspectSessions, SWT.BORDER);
-        text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+                                                        lblDebugInformation = new Label(compositeDebug, SWT.NONE);
+                                                        lblDebugInformation.setAlignment(SWT.CENTER);
+                                                        lblDebugInformation.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));
+                                                        lblDebugInformation.setFont(SWTResourceManager.getFont("Ubuntu", 10, SWT.NORMAL));
+                                                        lblDebugInformation.setText("Debug Information");
+
+                                                                                        txtDebugInfo = new Text(compositeDebug, SWT.BORDER | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
+                                                                                        txtDebugInfo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+                                sashForm.setWeights(new int[] {338, 184});
+
+        btnClose = new Button(shlInspectSessions, SWT.NONE);
+        btnClose.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                shlInspectSessions.dispose();
+            }
+        });
+        GridData gd_btnClose = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
+        gd_btnClose.widthHint = 70;
+        btnClose.setLayoutData(gd_btnClose);
+        btnClose.setText("Close");
 
     }
 
+    private void setDebugInfoText() {
+        txtDebugInfo.setText(ecdr.toString());
+    }
     private CdmEntityInfo[] getRootElements() {
-        EntityCacherDebugResult ecdr = activeSession.debug();
-        return (CdmEntityInfo[]) ecdr.getRootElements().toArray();
+
+        List<CdmEntityInfo> rootElemnts = ecdr.getRootElements();
+        return rootElemnts.toArray(new CdmEntityInfo[rootElemnts.size()]);
     }
 
     class SessionsTreeContentProvider implements ITreeContentProvider {
index baf62fab72d80a5b53a41ab976581ed1b3fd945e..406e977de0d172ac4206d9c8f96078cdfb98a7d5 100644 (file)
@@ -1,12 +1,12 @@
 // $Id$
 /**
-* Copyright (C) 2015 EDIT
-* European Distributed Institute of Taxonomy
-* http://www.e-taxonomy.eu
-*
-* The contents of this file are subject to the Mozilla Public License Version 1.1
-* See LICENSE.TXT at the top of this package for the full license terms.
-*/
+ * Copyright (C) 2015 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
 package eu.etaxonomy.taxeditor.view.sessions;
 
 import java.text.DecimalFormat;
@@ -33,6 +33,7 @@ import org.eclipse.ui.part.ViewPart;
 import org.eclipse.wb.swt.SWTResourceManager;
 
 import eu.etaxonomy.cdm.api.cache.CdmCacher;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
 import eu.etaxonomy.taxeditor.remoting.cache.CdmRemoteCacheManager;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
@@ -47,6 +48,7 @@ import eu.etaxonomy.taxeditor.store.CdmStore;
 public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManagerObserver {
 
     public static final String ID = "eu.etaxonomy.taxeditor.view.sessions.SessionsViewPart"; //$NON-NLS-1$
+    public static final String OPEN_INSPECT_SESSIONS_DIALOG_ID =  "eu.etaxonomy.taxeditor.store.open.InspectSessionsDialog";
     private Table tableSessions;
 
     private final String[] titles = { "Owner", "In Memory", "On Disk"};
@@ -58,6 +60,7 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
     private Text txtCdmModelInMemory;
     private Text txtCdmModelOnDisk;
     private Text txtDefaultOnDisk;
+
     public SessionsViewPart() {
         this.cdmEntitySessionManager = CdmStore.getCurrentSessionManager();
         if(cdmEntitySessionManager != null) {
@@ -72,7 +75,7 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
     @Override
     public void createPartControl(Composite parent) {
         Composite container = new Composite(parent, SWT.NONE);
-        container.setLayout(new GridLayout(6, false));
+        container.setLayout(new GridLayout(5, false));
         {
             Label lblNoOfSessions = new Label(container, SWT.NONE);
             lblNoOfSessions.setFont(SWTResourceManager.getFont("Ubuntu", 10, SWT.NORMAL));
@@ -94,7 +97,6 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
         new Label(container, SWT.NONE);
         new Label(container, SWT.NONE);
         new Label(container, SWT.NONE);
-        new Label(container, SWT.NONE);
         {
             Label lblNoOfCaches = new Label(container, SWT.CENTER);
             lblNoOfCaches.setAlignment(SWT.RIGHT);
@@ -113,16 +115,15 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
         }
         new Label(container, SWT.NONE);
         new Label(container, SWT.NONE);
-        new Label(container, SWT.NONE);
         new Label(container, SWT.NONE);
 
-                {
-                    Label lblDefaultCache = new Label(container, SWT.CENTER);
-                    lblDefaultCache.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
-                    lblDefaultCache.setText("Default Cache, ");
-                    lblDefaultCache.setFont(SWTResourceManager.getFont("Ubuntu", 10, SWT.NORMAL));
-                    lblDefaultCache.setAlignment(SWT.RIGHT);
-                }
+        {
+            Label lblDefaultCache = new Label(container, SWT.CENTER);
+            lblDefaultCache.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+            lblDefaultCache.setText("Default Cache, ");
+            lblDefaultCache.setFont(SWTResourceManager.getFont("Ubuntu", 10, SWT.NORMAL));
+            lblDefaultCache.setAlignment(SWT.RIGHT);
+        }
         {
             Label lblDefaultInMemory = new Label(container, SWT.CENTER);
             lblDefaultInMemory.setText("in Memory : ");
@@ -152,7 +153,6 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
             gd_txtDefaultOnDisk.widthHint = 130;
             txtDefaultOnDisk.setLayoutData(gd_txtDefaultOnDisk);
         }
-        new Label(container, SWT.NONE);
         {
             Label lblCdmModelCache = new Label(container, SWT.CENTER);
             lblCdmModelCache.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
@@ -191,7 +191,6 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
             gd_txtCdmModelOnDisk.widthHint = 130;
             txtCdmModelOnDisk.setLayoutData(gd_txtCdmModelOnDisk);
         }
-        new Label(container, SWT.NONE);
         {
             Button btnRefresh = new Button(container, SWT.NONE);
             btnRefresh.addSelectionListener(new SelectionAdapter() {
@@ -205,19 +204,28 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
             btnRefresh.setLayoutData(gd_btnRefresh);
             btnRefresh.setText("Refresh");
         }
-                new Label(container, SWT.NONE);
-                new Label(container, SWT.NONE);
-                new Label(container, SWT.NONE);
-                new Label(container, SWT.NONE);
-                new Label(container, SWT.NONE);
-
-                {
-                    tableSessions = new Table(container, SWT.BORDER | SWT.FULL_SELECTION);
-                    tableSessions.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 5, 1));
-                    tableSessions.setHeaderVisible(true);
-                    tableSessions.setLinesVisible(true);
+        {
+            Button btnInspectActiveSession = new Button(container, SWT.NONE);
+            btnInspectActiveSession.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    AbstractUtility.executeCommand(OPEN_INSPECT_SESSIONS_DIALOG_ID, this, null);
                 }
-                new Label(container, SWT.NONE);
+            });
+            btnInspectActiveSession.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
+            btnInspectActiveSession.setText("Inspect Active Session");
+        }
+        new Label(container, SWT.NONE);
+        new Label(container, SWT.NONE);
+
+        {
+            tableSessions = new Table(container, SWT.BORDER | SWT.FULL_SELECTION);
+            GridData gd_tableSessions = new GridData(SWT.FILL, SWT.FILL, true, true, 5, 1);
+            gd_tableSessions.widthHint = 769;
+            tableSessions.setLayoutData(gd_tableSessions);
+            tableSessions.setHeaderVisible(true);
+            tableSessions.setLinesVisible(true);
+        }
 
         createActions();
         initializeToolBar();
@@ -231,9 +239,9 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
 
 
         for (String title : titles) {
-          TableColumn column = new TableColumn(tableSessions, SWT.NULL);
-          column.setWidth(200);
-          column.setText(title);
+            TableColumn column = new TableColumn(tableSessions, SWT.NULL);
+            column.setWidth(200);
+            column.setText(title);
         }
         changed();
 
@@ -242,6 +250,9 @@ public class SessionsViewPart extends ViewPart implements ICdmEntitySessionManag
 
     @Override
     public void changed() {
+        if(tableSessions.isDisposed()) {
+            return;
+        }
         tableSessions.removeAll();
         if(cdmEntitySessionManager != null) {
             Collection<ICdmEntitySession> sessions = cdmEntitySessionManager.getSessions();