/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.harmony.luni.internal.io;

import java.util.HashMap;
import java.util.LinkedList;

/**
 * A simple cache implementation for file's canonical path. The cache has fixed
 * size <code> CACHE_SIZE </code> and cached elements would be expired. If
 * <code>put<code> method is invoked when cache is full, the oldest element will be removed.
 *
 */
public class FileCanonPathCache {

    static private class CacheElement {
        String canonicalPath;

        long timestamp;

        public CacheElement(String path) {
            this.canonicalPath = path;
            this.timestamp = System.currentTimeMillis();
        }
    }

    /**
     * Max elements could be hold in the cache.
     */
    public static final int CACHE_SIZE = 256;

    private static HashMap<String, CacheElement> cache = new HashMap<String, CacheElement>(
            CACHE_SIZE);

    /**
     * FIFO queue for tracking age of elements.
     */
    private static LinkedList<String> list = new LinkedList<String>();

    private static Object lock = new Object();

    /**
     * Expired time, 0 disable this cache.
     */
    private static long timeout = 30000;

    /**
     * Whether to enable this cache.
     */
    private static boolean isEnable = true;

    public static final String FILE_CANONICAL_PATH_CACHE_TIMEOUT = "org.apache.harmony.file.canonical.path.cache.timeout";

    static {
        String value = System.getProperty(FILE_CANONICAL_PATH_CACHE_TIMEOUT);
        try {
            timeout = Long.parseLong(value);
        } catch (NumberFormatException e) {
            // use default timeout value
        }

        if (timeout <= 0) {
            isEnable = false;
        }
    }

    /**
     * Retrieve element from cache.
     * 
     * @param path
     *            absolute path.
     * @return canonical path of <code>path</code> if it's in cache.
     * 
     */
    public static String get(String path) {
        if (!isEnable) {
            return null;
        }

        CacheElement element = null;
        synchronized (lock) {
            element = cache.get(path);
        }

        if (element == null) {
            return null;
        }

        long time = System.currentTimeMillis();
        if (time - element.timestamp > timeout) {
            // remove all elements older than this one
            synchronized (lock) {
                if (cache.get(path) != null) {
                    String oldest = null;
                    do {
                        oldest = list.removeFirst();
                        cache.remove(oldest);
                    } while (!path.equals(oldest));
                }
            }
            return null;
        }

        return element.canonicalPath;
    }

    /**
     * Put element to cache.
     * 
     * @param path
     *            absolute path.
     * @param canonicalPath
     *            the canonical path of <code>path</code>.
     */
    public static void put(String path, String canonicalPath) {
        if (!isEnable) {
            return;
        }

        CacheElement element = new CacheElement(canonicalPath);
        synchronized (lock) {
            if (cache.size() >= CACHE_SIZE) {
                // cache is full
                String oldest = list.removeFirst();
                cache.remove(oldest);
            }
            cache.put(path, element);
            list.addLast(path);
        }
    }

    /**
     * Remove all elements from cache.
     */
    public static void clear() {
        if (!isEnable) {
            return;
        }

        synchronized (lock) {
            cache.clear();
            list.clear();
        }
    }

    public static long getTimeout() {
        return timeout;
    }

    public static void setTimeout(long timeout) {
        FileCanonPathCache.timeout = timeout;
        if (timeout <= 0) {
            clear();
            isEnable = false;
        }
    }
}

@@ -1247,24 +1247,30 @@
 t %7B%0A        
+final 
 String canon
@@ -1280,32 +1280,38 @@
 lPath;%0A%0A        
+final 
 long timestamp;%0A
@@ -1597,16 +1597,22 @@
  static 
+final 
 HashMap%3C
@@ -1785,16 +1785,22 @@
  static 
+final 
 LinkedLi
@@ -1863,16 +1863,22 @@
  static 
+final 
 Object l
@@ -1972,24 +1972,33 @@
 vate static 
+volatile 
 long timeout
@@ -2012,106 +2012,8 @@
 0;%0A%0A
-    /**%0A     * Whether to enable this cache.%0A     */%0A    private static boolean isEnable = true;%0A%0A
     
@@ -2391,33 +2391,32 @@
    if (timeout %3C
-=
  0) %7B%0A          
@@ -2417,32 +2417,27 @@
         
-isEnable = false
+timeout = 0
 ;%0A      
@@ -2684,37 +2684,82 @@
 ) %7B%0A        
-if (!isEnable
+long localTimeout = timeout;%0A        if (localTimeout == 0
 ) %7B%0A        
@@ -3057,17 +3057,22 @@
 stamp %3E 
-t
+localT
 imeout) 
@@ -3804,33 +3804,36 @@
         if (
-!isEnable
+timeout == 0
 ) %7B%0A        
@@ -4323,17 +4323,20 @@
 if (
-!isEnable
+timeout == 0
 ) %7B%0A
@@ -4597,54 +4597,75 @@
     
-FileCanonPathCache.timeout = timeout;%0A
+synchronized (lock) %7B%0A            if (timeout %3C= 0) %7B%0A     
         
 if (
@@ -4656,36 +4656,35 @@
             
-if (
+   
 timeout 
 %3C= 0) %7B%0A    
@@ -4667,32 +4667,33 @@
     timeout 
-%3C
 = 0
-) %7B%0A
+;%0A    
             
@@ -4717,24 +4717,58 @@
     
-isEnable = false
+%7D%0A            FileCanonPathCache.timeout = timeout
 ;%0A  

Improve patch for HARMONY-6675 at r1035930: remove field 'isEnable' and mark more fileds as 'final'.