swingx-ws
  1. swingx-ws
  2. SWINGX_WS-15

More advanced disk cache implementation

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: initial
    • Fix Version/s: 1.1
    • Component/s: www
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      15

      Description

      See also http://forums.java.net/jive/thread.jspa?messageID=293660

      In the latest dev builds the TileCache class is extendable and the
      DefaultTileCacheFactory has a public setter for a custom cache implementation.

      I refactored the old sources and now this one will work with the latest dev
      version again (tested against the build of august 3 2008). Also I followed the
      advice of Fabrizio Giudici to use MD5 hashed names for cached files.

      To install the cache:

      File lCacheDir = new File(System.getProperty("user.home") + File.separator +
      ".swingx");
      lTileCache = CustomTileCache.getInstance(lCacheDir);
      lDefaultFactory.setTileCache(lTileCache);

      CustomTileCache.java:

      import org.jdesktop.swingx.mapviewer.TileCache;

      import javax.imageio.ImageIO;
      import java.awt.image.BufferedImage;
      import java.io.*;
      import java.net.URI;
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.util.logging.Level;
      import java.util.logging.Logger;

      /*

      • ============================================================================
      • Created: May 12, 2007 1:49:17 AM
      • ============================================================================
        */

      /**

      • Install custom cache hashmap implementation for SwingX mapviewer build 20070506
      • Map<URI, byte[]>
        */
        public class CustomTileCache extends TileCache {

      private static Logger logger = Logger.getLogger(CustomTileCache.class.getName());

      private static CustomTileCache instance;

      // instance variables

      private File cacheDir;
      // Max cache size in bytes
      private long maxCacheSize = 100 * 1024 * 1024;
      // Max age of cached tile in days
      private int maxAge = 30;

      /**

      • Private constructor, create instance through createInstance() methode
        */
        private CustomTileCache(File pCacheDir) { cacheDir = pCacheDir; }


        @Override
        public void put(URI pURI, byte[] pImgBytes, BufferedImage pImage) {
        super.put(pURI, pImgBytes, pImage);
        synchronized (this) { putImageData(pURI.toString(), pImgBytes); }
        }


        @Override
        public BufferedImage get(URI pURI) throws IOException {

        BufferedImage lImage = super.get(pURI);
        synchronized (this) {
        if (lImage == null && containsImageURI(pURI)) { byte[] lImageBytes = getImageData(pURI); lImage = ImageIO.read(new ByteArrayInputStream(lImageBytes)); super.put(pURI, lImageBytes, lImage); return lImage; }
        }

        // Not found
        return lImage;
        }


        /**
        * Test if file exists based on given URI
        */
        private boolean containsImageURI(URI pFullImageURI) { File lFile = new File(cacheDir, toMD5Hash(pFullImageURI.toString())); return lFile.isFile() && !isTooOld(lFile, instance.getMaxAge()); }


        public byte[] getImageData(URI pFullImageURI) throws IOException {

        // return byte array with compressed image contents
        if (containsImageURI(pFullImageURI)) { File lFile = new File(cacheDir, toMD5Hash(pFullImageURI.toString())); logger.info("Load cached file: " + lFile); return copyFile(lFile); }

        // Not found
        return null;
        }


        public void putImageData(String pFullImageUrlName, byte[] pData) {

        if (logger.isLoggable(Level.INFO)) { logger.info("Caching: " + pFullImageUrlName + ", size: " + pData.length); }

        File lFile = new File(cacheDir, toMD5Hash(pFullImageUrlName));
        try { copyFile(pData, lFile); } catch (IOException e) { logger.log(Level.WARNING, "Error saving file " + lFile, e); }
        }


        // ===================================
        // Getters and setters
        // ===================================

        public File getCacheDir() { return cacheDir; }

        public void setCacheDir(File pCacheDir) { cacheDir = pCacheDir; }

      public long getMaxCacheSize()

      { return maxCacheSize; }

      public void setMaxCacheSize(long pMaxCacheSize)

      { maxCacheSize = pMaxCacheSize; }

      public int getMaxAge()

      { return maxAge; }

      public void setMaxAge(int pMaxAgeInDays)

      { maxAge = pMaxAgeInDays; }

      // ===================================
      // Utility methods
      // ===================================

      /**

      • Install custom cache
        */
        public static synchronized CustomTileCache getInstance(File pCacheDir) {

      // Only one instance
      if (instance != null)

      { return instance; }

      if (!pCacheDir.isDirectory())

      { pCacheDir.mkdirs(); }

      instance = new CustomTileCache(pCacheDir);
      return instance;
      }

      /**

      • Clean cache, remove everything older then maxAge
      • The new max size of cache will be the value of maxCacheSize
        *
      • @param pFullClean When true, erase all files in cache and remove cache dir
        */
        public static void cleanCache(boolean pFullClean) {

      if (instance == null)

      { return; }

      File lCacheDirectory = instance.getCacheDir();
      if (!lCacheDirectory.exists())

      { logger.info("Cache dir does not exist, nothing to clean"); return; }

      StringBuilder lResult = new StringBuilder();
      for (File lFile : lCacheDirectory.listFiles()) {

      if (pFullClean || isTooOld(lFile, instance.getMaxAge())) {
      lFile.delete();
      if (logger.isLoggable(Level.INFO))

      { lResult.append(" Deleted: ").append(lFile).append("\n"); }

      }
      }

      if (pFullClean)

      { lCacheDirectory.delete(); }

      if (logger.isLoggable(Level.INFO) && lResult.length() > 0)

      { logger.info("Cache files removed: \n" + lResult); }

      }

      /**

      • Copy byte array to geven file
        */
        public static void copyFile(byte[] inFile, File outFile) throws IOException {

      FileOutputStream lStream = null;
      try

      { lStream = new FileOutputStream(outFile); BufferedOutputStream os = new BufferedOutputStream(lStream); os.write(inFile, 0, inFile.length); os.close(); }

      finally {
      if (lStream != null) {
      try

      { lStream.close(); } catch (Exception e) { // NOP }
      }
      }
      }


      /**
      * copy file to byte array
      */
      public static byte[] copyFile(File pInFile) throws IOException {

      FileInputStream lStream = null;
      try {
      lStream = new FileInputStream(pInFile);
      ByteArrayOutputStream lOutFile = new ByteArrayOutputStream();
      BufferedInputStream is = new BufferedInputStream(lStream);
      BufferedOutputStream os = new BufferedOutputStream(lOutFile);

      //Read and write until done
      byte[] buf = new byte[4096];
      int len;

      //Buffercopy
      while ((len = is.read(buf)) >= 0) { os.write(buf, 0, len); }

      is.close();
      os.close();
      return lOutFile.toByteArray();

      } finally {
      if (lStream != null) {
      try { lStream.close(); }

      catch (IOException e)

      { // NOP }

      }
      }
      }

      /**

      • Test if given file is older then maxAge
        *
      • @return Return true if older
        */
        public static boolean isTooOld(File pFile, int pMaxAgeInDays) { long lNow = System.currentTimeMillis(); long lHistory = lNow - 1000L * 60 * 60 * 24 * pMaxAgeInDays; return (pFile.lastModified() < lHistory); }

      /**

      • Encode string MD5, results in HEX
        */
        public static String toMD5Hash(String pKey) {

      String lRestring = "";
      try

      { MessageDigest lMessageDigest = MessageDigest.getInstance("MD5"); lMessageDigest.update(pKey.getBytes()); byte lResult[] = lMessageDigest.digest(); lRestring = toHexCode(lResult); }

      catch (NoSuchAlgorithmException e)

      { logger.log(Level.SEVERE, "No such algorithm", e); }

      return lRestring;
      }

      /**

      • Convert byte array to hex code equivalent
        */
        private static String toHexCode(byte pByteArray[]) {

      StringBuffer lBuffer = new StringBuffer(pByteArray.length * 2);
      for (byte lHash : pByteArray) {
      if ((lHash & 0xff) < 16)

      { lBuffer.append("0"); }

      lBuffer.append(Long.toString(lHash & 0xff, 16));
      }

      return lBuffer.toString().toUpperCase();
      }
      }

      Rob Juurlink

        Activity

        Hide
        rah003 added a comment -

        Bumped to the next version.

        Show
        rah003 added a comment - Bumped to the next version.

          People

          • Assignee:
            swingx-ws-issues
            Reporter:
            kozmoz2
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated: