Package com.granule.cache

Source Code of com.granule.cache.FileCache

/*
* Copyright 2010 Granule Inc.
*
* 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 com.granule.cache;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;

import javax.servlet.ServletContext;

import com.granule.CachedBundle;
import com.granule.CompressorSettings;
import com.granule.FragmentDescriptor;
import com.granule.IRequestProxy;
import com.granule.JSCompileException;
import com.granule.json.JSONException;
import com.granule.json.JSONObject;
import com.granule.logging.Logger;
import com.granule.logging.LoggerFactory;
import com.granule.utils.PathUtils;

/**
* User: Dario Wunsch Date: 12.09.2010 Time: 4:05:16
*/
public class FileCache extends TagCacheImpl {

  /*
   * Default pathname (it is abstract name reference to context path of web
   * app) Started from . to mark path as not absolute in the Unix File Systems
   */
  private static final String DEFAULT_CACHE_FOLDER = "./granulecache";
  private static final String CATALOG_JSON = "catalog.json";

  protected static TagCacheImpl instance = new FileCache();

  private String cacheFolder;
  private BufferedOutputStream catalog;

  private FileCache() {
    super();
  }

  /*
   * Singleton instance
   */

  public static TagCacheImpl getInstance() {
    return instance;
  }

  public String compressAndStore(IRequestProxy request,
      CompressorSettings settings,
      List<FragmentDescriptor> fragmentDescriptors, boolean isJs,
      String options) throws JSCompileException {

    logger.debug("FileCache compressAndStore");

    String signature = generateSignature(settings, fragmentDescriptors,
        options, isJs);

    // Try to identify if it was already compiled
    String id;
    if (settings.getCache().equalsIgnoreCase("none"))
      id = null;
    else
      synchronized (this) {
        id = signatureToId.get(signature);
      }

    // If it wasn't then compress it
    if (id == null) {
      CachedBundle cs = new CachedBundle();
      cs.setFragments(fragmentDescriptors);
      cs.setOptions(options);
      if (isJs)
        cs.compileScript(settings, request);
      else
        cs.compileCss(settings, request);
      synchronized (this) {
        id = generateId(signature);
        signatureToId.put(signature, id);
        bundles.put(id, cs);

        saveBundle(id, cs);
      }
    }
    return id;
  }

  private void saveBundle(String id, CachedBundle cs) {
    try {
      String filename = "/" + id + ".gzip."
          + (cs.isScript() ? "js" : "css");
      File f = new File(cacheFolder + filename);
      BufferedOutputStream bos = new BufferedOutputStream(
          new FileOutputStream(f));
      try {
        bos.write(cs.getBundleValue());
      } finally {
        bos.close();
      }
      cs.setModifyDate(f.lastModified());
     
      //f.setLastModified(System.currentTimeMillis());// cs.getModifyDate());
            String json = cs.getJSONString(id);
      catalog.write(json.getBytes("UTF-8"));
      catalog.flush();
    } catch (Exception e) {
      logger.error("Could not save bundle:", e);
    }
  }

  public CachedBundle getCompiledBundle(IRequestProxy request,
      CompressorSettings settings, String id) throws JSCompileException {
    logger.debug("FileCache getCompiledBundle");
    CachedBundle bundle = null;
    synchronized (this) {
      bundle = bundles.get(id);
    }
    if (bundle != null && settings.isCheckTimestamps()) {
      synchronized (bundle) {
        if (bundle.isChanged(request)) {
          if (bundle.getOptions() != null)
            settings.setOptions(bundle.getOptions());
          bundle.compile(settings, request);
          synchronized (this) {
            saveBundle(id, bundle);
          }
        }
      }
    }
    return bundle;
  }

  private boolean readCache(String catalog, ServletContext context)
      throws JSONException, IOException, JSCompileException {
    BufferedReader reader = new BufferedReader(new FileReader(catalog));
    boolean needRebuildCache;
    try {
      String line;
      needRebuildCache = false;
      while ((line = reader.readLine()) != null) {
        try {
          JSONObject obj = new JSONObject(line);
          String id = obj.getString("id");
          if (bundles.containsKey(id)) {
            logger.warn("Rebuilding from dublicate id");
            needRebuildCache = true;
          }
          CachedBundle cs = new CachedBundle();
          cs.loadFromJSON(obj, cacheFolder);
          CompressorSettings settings = TagCacheFactory
              .getCompressorSettings(context.getRealPath("/"));
          if (cs.getOptions() != null)
            settings.setOptions(cs.getOptions());
          String signature = generateSignature(settings, cs
              .getFragments(), cs.getOptions(), cs.isScript());
          signatureToId.put(signature, id);
          bundles.put(id, cs);
        } catch (Exception e) {
          needRebuildCache = true;
          logger.error("Could not load bundle from catalog:", e);
        }
      }
    } finally {
      reader.close();
    }
    return needRebuildCache;
  }

  private static String expandEnvironmentStrings(String str) {
    StringBuilder sb = new StringBuilder();
    int start = 0;
    while (start < str.length()) {
      int startIndex = str.indexOf('%', start);
      if (startIndex < 0)
        break;
      else {
        int endIndex = str.indexOf('%', startIndex + 1);
        if (endIndex < 0)
          break;
        else {
          sb.append(str.substring(start, startIndex));
          if (startIndex + 1 == endIndex)
            sb.append("%");
          else {
            String varValue = System.getenv(str.substring(
                startIndex + 1, endIndex));
            sb.append(varValue == null ? "" : varValue);
          }
          start = endIndex + 1;
        }
      }
    }
    if (start < str.length())
      sb.append(str.substring(start, str.length()));
    return sb.toString();
  }

  private void rebuildCache(String catalogFilename) throws IOException,
      JSONException {
    BufferedOutputStream cat = new BufferedOutputStream(
        new FileOutputStream(catalogFilename));
    try {
      for (String id : bundles.keySet()) {
        String json = bundles.get(id).getJSONString(id);
        cat.write(json.getBytes("UTF-8"));
      }
    } finally {
      cat.close();
    }
  }

  private int deleteUnusedBundleFiles() {
    File f = new File(cacheFolder);
    String[] files = f.list(new FilenameFilter() {
      public boolean accept(File dir, String name) {
        if ((new File(dir.getAbsolutePath() + "/" + name).isDirectory()))
          return false;
        return (name.endsWith(".js") || name.endsWith(".css"));
      }
    });
    int deleted = 0;
    try {
      for (String s : files) {
        if (!bundles.containsKey(s.substring(0, s.indexOf(".")))) {
          (new File(cacheFolder + "/" + s)).delete();
          deleted++;
        }
      }
    } catch (Exception e) {
      logger.error("Error while deleting files from folder "
          + cacheFolder, e);
    }
    return deleted;
  }

  public void initForStandalone(String rootPath, CompressorSettings settings) {
    cacheFolder = calculateCacheLocation(settings, rootPath);
    emptyCacheFolder();
    String catalogFilename = getCacheCatalogFilePath();
    openCatalogFile(catalogFilename);
  }

  private void emptyCacheFolder() {
    // Delete all files in cacheFolder
    File[] files = (new File(cacheFolder)).listFiles();
    if (files != null)
      for (File f : files)
        f.delete();
  }

  public void initWeb(ServletContext context, CompressorSettings settings) {
    logger.debug("FileCache init");
    String rootPath = context.getRealPath("/");

    cacheFolder = calculateCacheLocation(settings, rootPath);

    String catalogFilename = getCacheCatalogFilePath();
    if ((new File(catalogFilename)).exists())
      try {
        boolean needRebuildCache = readCache(catalogFilename, context);
        if (needRebuildCache) {
          emptyCacheFolder();
          rebuildCache(catalogFilename);
        } else {
          if (deleteUnusedBundleFiles() > 0)
            rebuildCache(catalogFilename);
        }
      } catch (Exception e) {
        logger.error("Error while reading cache catalog", e);
      }

    openCatalogFile(catalogFilename);
  }

  private void openCatalogFile(String catalogFilename) {
    try {
      File f = new File(cacheFolder);
      if (!f.exists())
        f.mkdirs();
      catalog = new BufferedOutputStream(new FileOutputStream(
          catalogFilename, true));
    } catch (Exception e) {
      logger.error("Error while opening catalog for writing", e);
    }
  }

  private String calculateCacheLocation(CompressorSettings settings,
      String rootPath) {
    String cacheFolder;
    if (settings.getCacheFileLocation() == null)
      cacheFolder = DEFAULT_CACHE_FOLDER;
    else
      cacheFolder = settings.getCacheFileLocation();
    cacheFolder = expandEnvironmentStrings(cacheFolder);
    if (!(new File(cacheFolder).isAbsolute()))
      cacheFolder = rootPath + "/" + cacheFolder;
    cacheFolder = PathUtils.clean(cacheFolder);
    logger.info(MessageFormat.format("Granule FileCache location is {0}",
        cacheFolder));
    return cacheFolder;
  }

  private String getCacheCatalogFilePath() {
    return cacheFolder + "/"+CATALOG_JSON;
  }

  private static final Logger logger = LoggerFactory
      .getLogger(FileCache.class);
}
TOP

Related Classes of com.granule.cache.FileCache

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.