package com.ai.tris.server.cache;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;

/**
 * Cache Factory.
 * <p/>
 * Created by Sam on 2015/6/7.
 */
public class CacheFactory {

    /**
     * Store cache data.
     */
    private static Map<String, Map<String, Object>> CACHE = new HashMap<>();

    private static Set<Class<?>> CACHE_IMPL_SET = new HashSet<>();

    private static ReentrantLock readWriteLock = new ReentrantLock();

    private static transient Log logger = LogFactory.getLog(CacheFactory.class);

    static {
        loadAllData();
    }

    /**
     * Get cached map. If list kind data is wanted, this method can do
     * such the thing.
     *
     * @param cacheItem cache item key
     * @return cached map value
     */
    public static Map<String, Object> getCacheData(String cacheItem) {
        readWriteLock.lock();
        Map<String, Object> cachedMap = CACHE.get(cacheItem);
        readWriteLock.unlock();
        return (null != cachedMap && cachedMap.size() > 0) ? cachedMap : new HashMap<String, Object>(0);
    }

    /**
     * Get cache data. Using ReentrantLock is used for for synchronization control.
     *
     * @param cacheItem cache item key
     * @param cacheKey  cache key
     * @return cached data.
     */
    public static Object getCacheData(String cacheItem, String cacheKey) {
        readWriteLock.lock();
        Map<String, Object> cachedItem = CACHE.get(cacheItem);
        readWriteLock.unlock();
        if (null != cachedItem) {
            return cachedItem.get(cacheKey);
        }
        return null;
    }

    /**
     * Get cache data. Using ReentrantLock is used for for synchronization control.
     *
     * @param cacheItem cache item key
     * @param cacheKey  cache key
     * @return cached data.
     */
    public static String getCacheDataString(String cacheItem, String cacheKey) {
        Object temp;
        return (temp = getCacheData(cacheItem, cacheKey)) == null ? null : String.valueOf(temp);
    }

    /**
     * Load all data to cache.
     */
    public static void loadAllData() {
        readWriteLock.lock();
        readCacheImpl();
        if (CACHE_IMPL_SET.size() > 0) {
            for (Class cacheImpl : CACHE_IMPL_SET) {
                try {
                    try {
                        ICache iCache = (ICache) (cacheImpl.newInstance());
                        CACHE.put(iCache.getClass().getName(), iCache.loadData());
                    } catch (InstantiationException ie) {
                        logger.error(String.format("cache %s load failed.", cacheImpl.getClass().getName()), ie);
                    }
                } catch (IllegalAccessException iae) {
                    logger.error(String.format("cache %s load failed.", cacheImpl.getClass().getName()), iae);
                }
            }
        }
        readWriteLock.unlock();
    }

    public static void reloadAll() {
    }

    public static void reload(String cacheItem) {
    }

    private static void readCacheImpl() {
        try {
            Properties prop = new Properties();
            prop.load(CacheFactory.class.getClassLoader().getResourceAsStream("server.properties"));
            String cacheClasses = prop.getProperty("cache.classes");
            if (StringUtils.isEmpty(cacheClasses)) {
                if (logger.isInfoEnabled()) {
                    logger.info("No cache to load.");
                }
                return;
            }
            String[] cachePieces = cacheClasses.split(Pattern.quote(","));
            for (String cacheClassName : cachePieces) {
                Class cacheClass = Class.forName(cacheClassName.trim());
                Class[] interfaces = cacheClass.getInterfaces();
                for (Class _interface : interfaces) {
                    if (_interface.getName().equals(ICache.class.getName())) {
                        CACHE_IMPL_SET.add(cacheClass);
                    }
                }
            }
        } catch (IOException ioe) {
            logger.error("Load server.properties failed.", ioe);
            throw new RuntimeException("Load server.properties failed.");
        } catch (ClassNotFoundException cnfe) {
            logger.error("Class not found exception.", cnfe);
            throw new RuntimeException("Class not found exception.");
        }

    }
}

@@ -1017,32 +1017,49 @@
 ng cacheItem) %7B%0A
+        try%7B%0A    
         readWrit
@@ -1064,32 +1064,36 @@
 iteLock.lock();%0A
+    
         Map%3CStri
@@ -1146,36 +1146,8 @@
     
-    readWriteLock.unlock();%0A
     
@@ -1247,16 +1247,82 @@
 ct%3E(0);%0A
+        %7D finally %7B%0A            readWriteLock.unlock();%0A        %7D%0A
     %7D%0A%0A 
@@ -1595,32 +1595,49 @@
 ing cacheKey) %7B%0A
+        try%7B%0A    
         readWrit
@@ -1642,32 +1642,36 @@
 iteLock.lock();%0A
+    
         Map%3CStri
@@ -1726,43 +1726,15 @@
     
-   readWriteLock.unlock();%0A
        
- 
 if (
@@ -1747,32 +1747,36 @@
 = cachedItem) %7B%0A
+    
             retu
@@ -1804,34 +1804,42 @@
 heKey);%0A        
+   
+ 
 %7D%0A
+    
         return n
@@ -1843,16 +1843,82 @@
 n null;%0A
+        %7D finally %7B%0A            readWriteLock.unlock();%0A        %7D%0A
     %7D%0A%0A 
@@ -2412,24 +2412,41 @@
 AllData() %7B%0A
+        try%7B%0A    
         read
@@ -2455,32 +2455,36 @@
 iteLock.lock();%0A
+    
         readCach
@@ -2496,24 +2496,28 @@
 ();%0A        
+    
 if (CACHE_IM
@@ -2541,32 +2541,36 @@
 ) %7B%0A            
+   
+ 
 for (Class cache
@@ -2602,32 +2602,36 @@
                 
+    
 try %7B%0A          
@@ -2632,38 +2632,46 @@
                 
+  
+  
 try %7B%0A
+    
                 
@@ -2750,24 +2750,28 @@
             
+ 
+   
 CACHE.put(iC
@@ -2813,24 +2813,28 @@
 oadData());%0A
+    
             
@@ -2895,32 +2895,36 @@
                 
+    
 logger.error(Str
@@ -3009,34 +3009,42 @@
                 
+   
+ 
 %7D%0A
+    
                 
@@ -3078,24 +3078,28 @@
 tion iae) %7B%0A
+    
             
@@ -3205,34 +3205,42 @@
                 
-%7D%0A
+    %7D%0A    
             %7D%0A  
@@ -3237,34 +3237,62 @@
       %7D%0A        
+  
+  
 %7D%0A
+        %7D finally %7B%0A    
         readWrit
@@ -3303,24 +3303,34 @@
 k.unlock();%0A
+        %7D%0A
     %7D%0A%0A    p

add try-finally to use lock correctly