Package org.apache.commons.vfs.cache

Source Code of org.apache.commons.vfs.cache.SoftRefFilesCache$SoftRefReleaseThread

/*
* Copyright 2002-2005 The Apache Software Foundation.
*
* Licensed 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.commons.vfs.cache;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystem;
import org.apache.commons.vfs.VfsLog;
import org.apache.commons.vfs.impl.DefaultFileSystemManager;
import org.apache.commons.vfs.util.Messages;

/**
* This implementation caches every file as long as it is strongly reachable by
* the java vm. As soon as the vm needs memory - every softly reachable file
* will be discarded.
*
* @author <a href="mailto:imario@apache.org">Mario Ivankovits</a>
* @see SoftReference
*/
public class SoftRefFilesCache extends AbstractFilesCache
{
  /**
   * The logger to use.
   */
  private Log log = LogFactory.getLog(SoftRefFilesCache.class);

  private final Map filesystemCache = new HashMap();
  private final Map refReverseMap = new HashMap(100);
  private final ReferenceQueue refqueue = new ReferenceQueue();

  private SoftRefReleaseThread softRefReleaseThread = null;

  /**
   * This thread will listen on the ReferenceQueue and remove the entry in the
   * filescache as soon as the vm removes the reference
   */
  private class SoftRefReleaseThread extends Thread
  {
    private boolean requestEnd = false;

    private SoftRefReleaseThread()
    {
      setName(SoftRefReleaseThread.class.getName());
      setDaemon(true);
    }

    public void run()
    {
      loop: while (!requestEnd && !Thread.currentThread().isInterrupted())
      {
        try
        {
          Reference ref = refqueue.remove(1000);
          if (ref == null)
          {
            continue;
          }

          FileSystemAndNameKey key = (FileSystemAndNameKey) refReverseMap
              .get(ref);

          if (key != null)
          {
            if (removeFile(key))
            {
              filesystemClose(key.getFileSystem());
            }
          }
        }
        catch (InterruptedException e)
        {
          if (!requestEnd)
          {
            VfsLog
                .warn(
                    getLogger(),
                    log,
                    Messages
                        .getString("vfs.impl/SoftRefReleaseThread-interrupt.info"));
          }
          break loop;
        }
      }
    }
  }

  public SoftRefFilesCache()
  {
  }

  private void startThread()
  {
    if (softRefReleaseThread != null)
    {
      throw new IllegalStateException(
          Messages
              .getString("vfs.impl/SoftRefReleaseThread-already-running.warn"));
    }

    softRefReleaseThread = new SoftRefReleaseThread();
    softRefReleaseThread.start();
  }

  private void endThread()
  {
    if (softRefReleaseThread != null)
    {
      softRefReleaseThread.requestEnd = true;
      softRefReleaseThread.interrupt();
      softRefReleaseThread = null;
    }
  }

  public void putFile(final FileObject file)
  {
    if (log.isDebugEnabled())
    {
      log.debug("putFile: " + file.getName());
    }

    Map files = getOrCreateFilesystemCache(file.getFileSystem());

    Reference ref = new SoftReference(file, refqueue);
    FileSystemAndNameKey key = new FileSystemAndNameKey(file
        .getFileSystem(), file.getName());

    synchronized (files)
    {
      files.put(file.getName(), ref);
      refReverseMap.put(ref, key);
    }
  }

  public FileObject getFile(final FileSystem filesystem, final FileName name)
  {
    Map files = getOrCreateFilesystemCache(filesystem);

    synchronized (files)
    {
      SoftReference ref = (SoftReference) files.get(name);
      if (ref == null)
      {
        return null;
      }

      FileObject fo = (FileObject) ref.get();
      if (fo == null)
      {
        removeFile(filesystem, name);
      }
      return fo;
    }
  }

  public void clear(FileSystem filesystem)
  {
    Map files = getOrCreateFilesystemCache(filesystem);

    boolean closeFilesystem;

    synchronized (files)
    {
      Iterator iterKeys = refReverseMap.values().iterator();
      while (iterKeys.hasNext())
      {
        FileSystemAndNameKey key = (FileSystemAndNameKey) iterKeys
            .next();
        if (key.getFileSystem() == filesystem)
        {
          iterKeys.remove();
          files.remove(key.getFileName());
        }
      }

      closeFilesystem = files.size() < 1;
    }

    if (closeFilesystem)
    {
      filesystemClose(filesystem);
    }
  }

  private void filesystemClose(FileSystem filesystem)
  {
    if (log.isDebugEnabled())
    {
      log.debug("close fs: " + filesystem.getRootName());
    }
    synchronized (filesystemCache)
    {
      filesystemCache.remove(filesystem);
      if (filesystemCache.size() < 1)
      {
        endThread();
      }
    }
    ((DefaultFileSystemManager) getContext().getFileSystemManager())
        .closeFileSystem(filesystem);
  }

  public void close()
  {
    super.close();

    endThread();

    // files.clear();
    synchronized (filesystemCache)
    {
      filesystemCache.clear();
    }
    refReverseMap.clear();
  }

  public void removeFile(FileSystem filesystem, FileName name)
  {
    if (removeFile(new FileSystemAndNameKey(filesystem, name)))
    {
      filesystemClose(filesystem);
    }
  }

  public void touchFile(FileObject file)
  {
  }

  private boolean removeFile(final FileSystemAndNameKey key)
  {
    if (log.isDebugEnabled())
    {
      log.debug("removeFile: " + key.getFileName());
    }

    Map files = getOrCreateFilesystemCache(key.getFileSystem());

    synchronized (files)
    {
      Object ref = files.remove(key.getFileName());
      if (ref != null)
      {
        refReverseMap.remove(ref);
      }

      return files.size() < 1;
    }
  }

  protected Map getOrCreateFilesystemCache(final FileSystem filesystem)
  {
    synchronized (filesystemCache)
    {
      if (filesystemCache.size() < 1)
      {
        startThread();
      }

      Map files = (Map) filesystemCache.get(filesystem);
      if (files == null)
      {
        files = new TreeMap();
        filesystemCache.put(filesystem, files);
      }

      return files;
    }
  }
}
TOP

Related Classes of org.apache.commons.vfs.cache.SoftRefFilesCache$SoftRefReleaseThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.