001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.services; 019 020import io.stallion.Context; 021import org.apache.commons.codec.digest.DigestUtils; 022import org.apache.commons.io.FileUtils; 023import org.apache.commons.io.IOUtils; 024 025import java.io.File; 026import java.io.IOException; 027import java.security.MessageDigest; 028import java.util.Map; 029 030import static io.stallion.utils.Literals.*; 031 032/** 033 * A service that stores values semi-permanently both in the local file system 034 * and in memory. 035 * 036 * All values will live in memory as long as the process does, and in the file system as 037 * long as the cache is not cleaned. 038 * 039 * This should only be used for bounded data, otherwise memory could explode. 040 * 041 * 042 * 043 */ 044public class PermaCache { 045 private static final Map<String, String> cache = map(); 046 private static String cacheFolder; 047 048 public static String get(String key) { 049 if (cache.containsKey(key)) { 050 return cache.get(key); 051 } 052 if (!empty(getCacheFolder())) { 053 File file = new File(getCacheFolder() + "/" + DigestUtils.md5Hex(key)); 054 if (file.exists()) { 055 try { 056 String content = FileUtils.readFileToString(file, "utf-8"); 057 cache.put(key, content); 058 return content; 059 } catch (IOException e) { 060 Log.exception(e, "Error reading file from disk: " + file.toString()); 061 } 062 } 063 } 064 return null; 065 } 066 067 public static void set(String key, String contents) { 068 cache.put(key, contents); 069 if (!empty(getCacheFolder())) { 070 File file = new File(getCacheFolder() + "/" + DigestUtils.md5Hex(key)); 071 try { 072 FileUtils.write(file, contents, "utf-8"); 073 } catch (IOException e) { 074 Log.exception(e, "Error writing file to cache: " + file.toString()); 075 } 076 } 077 } 078 079 public static void setInMemoryOnly(String key, String contents) { 080 cache.put(key, contents); 081 } 082 083 public static String getCacheFolder() { 084 if (cacheFolder == null) { 085 cacheFolder = initCacheFolder(); 086 } 087 return cacheFolder; 088 } 089 090 public static String initCacheFolder() { 091 File tmp = new File("/tmp/stallion-cache"); 092 if (tmp.isDirectory() && tmp.canWrite()) { 093 return "/tmp/stallion-cache"; 094 } 095 Boolean made = tmp.mkdirs(); 096 if (made) { 097 return "/tmp/stallion-cache"; 098 } 099 String appCachePath = Context.settings().getDataDirectory() + "/_cache"; 100 tmp = new File(appCachePath); 101 if (tmp.isDirectory() && tmp.canWrite()) { 102 return appCachePath; 103 } 104 made = tmp.mkdirs(); 105 if (made) { 106 return appCachePath; 107 } 108 Log.warn("Could not create cache folder /tmp/stallion-cache or {0}!", appCachePath); 109 return ""; 110 } 111 112}