ref #10222 add agentlink to taxonNodeAgentRelDto
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / PreferenceServiceImpl.java
index d9792271406faf52db37338e6e4e578108a31959..f1f157c0bc4549df8dfeb888a3ead86fa3573cef 100644 (file)
 package eu.etaxonomy.cdm.api.service;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -20,12 +24,16 @@ import org.springframework.transaction.annotation.Transactional;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.metadata.CdmPreference;
 import eu.etaxonomy.cdm.model.metadata.CdmPreference.PrefKey;
-import eu.etaxonomy.cdm.model.metadata.PreferencePredicate;
+import eu.etaxonomy.cdm.model.metadata.IPreferencePredicate;
+import eu.etaxonomy.cdm.model.metadata.PreferenceResolver;
 import eu.etaxonomy.cdm.model.metadata.PreferenceSubject;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.persistence.dao.common.IPreferenceDao;
 
 /**
+ * Service to store and access {@link CdmPreference cdm preferences}.
+ * On how to use cdm preferences see the documentation there.
+ *
  * @author a.mueller
  * @since 2013-09-09
  */
@@ -34,75 +42,97 @@ import eu.etaxonomy.cdm.persistence.dao.common.IPreferenceDao;
 public class PreferenceServiceImpl implements IPreferenceService {
 
     @SuppressWarnings("unused")
-       private static final Logger logger = Logger.getLogger(PreferenceServiceImpl.class);
+    private static final Logger logger = LogManager.getLogger();
 
     @Autowired
     private IPreferenceDao dao;
 
-       @Override
-       public CdmPreference find(PrefKey key) {
-               List<PrefKey> keys = new ArrayList<>();
-               keys.add(key);
-//             while(key.)  TODO
+    private Map<String, CdmPreference> cache = new ConcurrentHashMap<>();
+
+    private boolean cacheIsComplete = false;
 
-               return dao.get(key);
+    private boolean cacheIsLocked = false;
+
+    @Override
+       public CdmPreference findExact(PrefKey key) {
+               String cacheKey = cacheKey(key);
+        return fromCacheGet(key, cacheKey);
        }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public CdmPreference findDatabase(PreferencePredicate predicate){
+    public CdmPreference find(PrefKey key) {
+        CdmPreference pref = PreferenceResolver.resolve(list(), key);
+        return pref;
+    }
+
+    @Override
+    public CdmPreference findDatabase(IPreferencePredicate<?> predicate){
         PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), predicate);
         return find(key);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public CdmPreference findVaadin(PreferencePredicate predicate){
+    public CdmPreference findVaadin(IPreferencePredicate<?> predicate){
         PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewVaadinInstance(), predicate);
         return find(key);
     }
 
     @Override
-    public CdmPreference findTaxEditor(PreferencePredicate predicate){
+    public CdmPreference findTaxEditor(IPreferencePredicate<?> predicate){
         PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewTaxEditorInstance(), predicate);
         return find(key);
     }
 
-
        @Override
     @Transactional(readOnly = false)
        public void set(CdmPreference preference) {
                dao.set(preference);
+               cachePut(preference);
        }
 
-       @Override
+    @Override
+    @Transactional(readOnly = false)
+    public void remove(PrefKey key) {
+        dao.remove(key);
+        removeFromCache(key);
+    }
+
+    @Override
        public long count() {
                return dao.count();
        }
 
        @Override
     public List<CdmPreference> list() {
-        return dao.list();
+           if(!cacheIsComplete) {
+               cacheFullUpdate();
+           }
+        return new ArrayList<>(cacheValues());
     }
 
     @Override
-    public Object find(TaxonNode taxonNode, String predicate) {
-        return dao.find(taxonNode, predicate);
+    public List<CdmPreference> list(IPreferencePredicate<?> predicate) {
+        // using the cache for this method makes not much sense
+        return dao.list(predicate);
     }
 
     @Override
-    public CdmPreference find(TaxonNode taxonNode, PreferencePredicate predicate){
-        return dao.find(taxonNode, predicate.getKey());
+    public CdmPreference find(TaxonNode taxonNode, String predicate) {
+
+        return dao.find(taxonNode, predicate);
+//      caching of taxon node related prefs disabled, see https://dev.e-taxonomy.eu/redmine/issues/9152#note-8
+//      code has been left here in case we decide later for solution 2 which has been suggested also in comment 5
+//        String cacheKey = cacheKey(taxonNode, predicate);
+//        return fromCacheOrFind(taxonNode, predicate, cacheKey);
     }
 
+    @Override
+    public CdmPreference find(TaxonNode taxonNode, IPreferencePredicate<?> predicate){
+        return find(taxonNode, predicate.getKey());
+    }
 
 // ********************** NOT YET HANDLED *******************/
 
-
     @Override
     public List<CdmPreference> list(String subject, String predicate) {
         //FIXME
@@ -116,10 +146,6 @@ public class PreferenceServiceImpl implements IPreferenceService {
         return dao.find(taxonNode, predicate);
     }
 
-    /**
-     * @param taxonNodeRelatedCdmBase
-     * @return
-     */
     private TaxonNode mapToTaxonNode(CdmBase taxonNodeRelatedCdmBase) {
         if (taxonNodeRelatedCdmBase == null){
             return null;
@@ -130,12 +156,84 @@ public class PreferenceServiceImpl implements IPreferenceService {
         }
     }
 
+    // ====================== Cache methods ======================= //
 
-//    @Override
-//    public String setCdmPrefs(CdmBase cdmBase, String predicate, String value) {
-//        // TODO Auto-generated method stub
-//        return null;
-//    }
+    /**
+     * Concatenates subject and predicate as key for the cache map
+     */
+    private String cacheKey(PrefKey key) {
+        return key.getSubject() + "@" + key.getPredicate();
+    }
+
+    /**
+     * @deprecated caching of taxon node related prefs disabled, see https://dev.e-taxonomy.eu/redmine/issues/9152#note-8
+     * code has been left here in case we decide later for solution 2 which has been suggested also in comment 5
+     */
+    @Deprecated
+    private String cacheKey(TaxonNode taxonNode, String predicate) {
+        return taxonNode.treeIndex() + predicate;
+    }
+
+
+    // --------------- non locking cache read methods --------------- //
 
+    protected Collection<CdmPreference> cacheValues() {
+        waitForCache();
+        return cache.values();
+    }
+
+    protected CdmPreference fromCacheGet(PrefKey key, String cacheKey) {
+        waitForCache();
+        return cache.computeIfAbsent(cacheKey, k -> dao.get(key));
+    }
+
+
+    /**
+     * @deprecated caching of taxon node related prefs disabled, see https://dev.e-taxonomy.eu/redmine/issues/9152#note-8
+     * code has been left here in case we decide later for solution 2 which has been suggested also in comment 5
+     */
+    @Deprecated
+    protected CdmPreference fromCacheOrFind(TaxonNode taxonNode, String predicate, String cacheKey) {
+        waitForCache();
+        return cache.computeIfAbsent(cacheKey, k -> dao.find(taxonNode, predicate));
+    }
+
+    // --------------- cache locking methods --------------- //
+
+    protected void cachePut(CdmPreference preference) {
+        waitForCache();
+        cacheIsLocked = true;
+        cache.put(cacheKey(preference.getKey()), preference);
+        cacheIsLocked = false;
+    }
+
+
+    protected void removeFromCache(PrefKey key) {
+        waitForCache();
+        cacheIsLocked = true;
+        cache.remove(cacheKey(key));
+        cacheIsLocked = false;
+    }
+
+    protected void cacheFullUpdate() {
+        waitForCache();
+        cacheIsLocked = true;
+        cache.clear();
+        for(CdmPreference pref :  dao.list()){
+            cache.put(cacheKey(pref.getKey()), pref);
+        }
+        cacheIsComplete = true;
+        cacheIsLocked = false;
+    }
+
+    protected void waitForCache() {
+        while(cacheIsLocked) {
+            try {
+                Thread.sleep(1);
+            } catch (InterruptedException e) {
+                // just keep on sleeping, we may improve this later on
+            }
+        }
+    }
 
 }