1 package info.magnolia.cms.cache.simple; 2 3 import info.magnolia.cms.cache.Cache; 4 import info.magnolia.cms.cache.CacheConfig; 5 import info.magnolia.cms.cache.CacheKey; 6 import info.magnolia.cms.cache.CacheableEntry; 7 import info.magnolia.cms.core.Path; 8 9 import java.io.File ; 10 import java.io.FileInputStream ; 11 import java.io.FileOutputStream ; 12 import java.io.IOException ; 13 import java.io.OutputStream ; 14 import java.util.Date ; 15 import java.util.Hashtable ; 16 import java.util.Map ; 17 import java.util.zip.GZIPOutputStream ; 18 19 import javax.servlet.http.HttpServletResponse ; 20 21 import org.apache.commons.io.FileUtils; 22 import org.apache.commons.io.IOUtils; 23 import org.apache.commons.lang.StringUtils; 24 import org.slf4j.Logger; 25 import org.slf4j.LoggerFactory; 26 27 28 36 public class CacheImpl implements Cache { 37 38 private static final Logger log = LoggerFactory.getLogger(CacheImpl.class); 39 40 43 private Map cachedURIList = new Hashtable (); 44 45 49 private static boolean currentlyRemoving; 50 51 private CacheConfig config; 52 53 59 public void cacheRequest(CacheKey key, CacheableEntry entry, boolean canCompress) { 60 if (currentlyRemoving) { 63 return; } 65 int compressedSize = 0; 66 File file = getFile(key, false); 67 68 if (file.isDirectory()) { 69 return; 71 } 72 73 if (!file.exists()) { 77 FileOutputStream out = null; 78 if (log.isDebugEnabled()) { 79 log.debug("creating file {}", file.getAbsolutePath()); 80 } 81 try { 82 file.getParentFile().mkdirs(); 83 file.createNewFile(); 84 85 out = new FileOutputStream (file); 86 out.write(entry.getOut()); 87 out.flush(); 88 } catch (Exception e) { 89 log.error("Failed to cache "+key.toString(), e); 90 } finally { 91 IOUtils.closeQuietly(out); 92 } 93 } 94 95 if (canCompress) { 96 File gzipFile = getFile(key, true); 97 if (!gzipFile.exists()) { 98 GZIPOutputStream gzipOut = null; 99 try { 100 gzipFile.getParentFile().mkdirs(); 101 gzipFile.createNewFile(); 102 FileOutputStream out = new FileOutputStream (gzipFile); 103 gzipOut = new GZIPOutputStream (out); 104 gzipOut.write(entry.getOut()); 105 gzipOut.flush(); 106 } catch (Exception e) { 107 log.error("Failed to create compressed entry for "+key.toString(), e); 108 } finally { 109 IOUtils.closeQuietly(gzipOut); 110 } 111 } 112 113 compressedSize = (new Long (gzipFile.length())).intValue(); 114 } 115 116 addToCachedURIList(key, new Date ().getTime(), (int) file.length(), compressedSize); 117 } 118 119 public synchronized void flush() { 120 try { 121 File cacheDir = getCacheDirectory(); 122 currentlyRemoving = true; 123 if (cacheDir.exists() && cacheDir.isDirectory()) { 124 FileUtils.deleteDirectory(cacheDir); 125 } 126 127 cacheDir.mkdirs(); 129 130 clearCachedURIList(); 132 } 133 catch (Throwable t) { 134 log.error(t.getMessage(), t); 135 } finally { 136 currentlyRemoving = false; 137 } 138 } 139 140 public long getCreationTime(CacheKey key) { 141 CachedItem item = (CachedItem) this.cachedURIList.get(key); 142 if (item == null) { 143 return -1; 144 } 145 146 return item.time; 147 } 148 149 public void start(CacheConfig config) { 150 this.config = config; 151 152 File cacheDir = getCacheDirectory(); 153 154 if (!cacheDir.exists()) { 155 boolean result = cacheDir.mkdirs(); 156 if (!result) { 157 log.error("Failed to create cache directory location {}", cacheDir.getAbsolutePath()); 158 } 159 } else { 160 updateInMemoryCache(cacheDir); 161 } 162 } 163 164 168 private void updateInMemoryCache(File cacheDir) { 169 File [] items = cacheDir.listFiles(); 170 for (int index=0; index < items.length; index++) { 171 File item = items[index]; 172 if (item.isDirectory()) { 173 updateInMemoryCache(item); 174 } else { 175 if (item.getName().lastIndexOf("gzip") < 0) { 176 String cacheHome = getCacheDirectory().getPath(); 178 CacheKey key = new CacheKey(StringUtils.substringAfter(item.getPath(), cacheHome)); 179 int size = (int) item.length(); 180 File compressedFile = new File (item.getPath()+".gzip"); 181 int compressedSize = -1; 182 if (compressedFile.exists()) compressedSize = (int) compressedFile.length(); 183 addToCachedURIList(key, item.lastModified(), size, compressedSize); 184 } 185 } 186 } 187 } 188 189 190 public boolean isCached(CacheKey key) { 191 return this.cachedURIList.get(key) != null; 192 } 193 194 public void stop() { 195 clearCachedURIList(); 198 } 199 200 207 public boolean streamFromCache(CacheKey key, HttpServletResponse response, boolean canCompress) { 208 209 FileInputStream fin = null; 210 OutputStream out = null; 211 try { 212 File file = getFile(key, canCompress); 213 214 if (!file.exists() || file.isDirectory() || file.length() < 4) { 215 return false; 216 } 217 218 if (log.isDebugEnabled()) { 219 log.debug("Streaming from cache the file: {}", file.getAbsolutePath()); } 221 222 fin = new FileInputStream (file); 223 out = response.getOutputStream(); 224 response.setDateHeader("Last-Modified", this.getCreationTime(key)); 225 if (canCompress) { 226 response.setContentLength(getCompressedSize(key)); 227 response.setHeader("Content-Encoding", "gzip"); 228 IOUtils.copy(fin, out); 229 } 230 else { 231 response.setContentLength(getSize(key)); 232 IOUtils.copy(fin, out); 233 } 234 out.flush(); 235 } 236 catch (IOException e) { 237 log.error("Error while reading cache for: '" + key + "'.", e); 238 return false; 239 } 240 finally { 241 IOUtils.closeQuietly(out); 242 IOUtils.closeQuietly(fin); 243 } 244 245 return true; 246 } 247 248 254 private void addToCachedURIList(CacheKey key, long lastModified, int size, int compressedSize) { 255 CachedItem entry = new CachedItem(lastModified, size, compressedSize); 256 257 if (log.isDebugEnabled()) { 258 log.debug("Caching URI [{}]", key); } 260 261 this.cachedURIList.put(key, entry); 262 } 263 264 private void clearCachedURIList() { 265 this.cachedURIList.clear(); 266 } 267 268 272 public void remove(CacheKey key) { 273 File file = this.getFile(key, false); 274 try { 275 if (file.isDirectory()) { 276 FileUtils.deleteDirectory(file); 277 clearCachedURIList(); 278 } 279 else { 280 if (log.isDebugEnabled()) { 281 log.debug("Flushing {}", file.getPath()); } 283 284 file.delete(); 285 removeFromCachedURIList(key); 286 } 287 } 288 catch (Exception e) { 289 log.error("Failed to flush [" + file.getPath() + "]: " + e.getMessage(), e); } 291 } 292 293 296 private int getCompressedSize(CacheKey key) { 297 CachedItem item = (CachedItem) this.cachedURIList.get(key); 298 if (item == null) { 299 return -1; 300 } 301 302 return item.compressedSize; 303 } 304 305 private File getFile(CacheKey key, boolean compressed) { 306 307 String fileName = key.toString(); 308 File cacheFile; 309 if (compressed) { 310 cacheFile = new File (getCacheDirectory(), fileName + ".gzip"); 311 } 312 else { 313 cacheFile = new File (getCacheDirectory(), fileName); 314 } 315 return cacheFile; 316 } 317 318 321 private int getSize(CacheKey key) { 322 CachedItem item = (CachedItem) this.cachedURIList.get(key); 323 if (item == null) { 324 return -1; 325 } 326 327 return item.size; 328 } 329 330 333 private void removeFromCachedURIList(CacheKey key) { 334 this.cachedURIList.remove(key); 335 } 336 337 private File getCacheDirectory() { 338 339 return new File (Path.getCacheDirectory(), "mgnl-cache"); 342 } 343 344 private static class CachedItem { 345 346 349 protected int compressedSize; 350 351 354 protected int size; 355 356 359 protected long time; 360 361 public CachedItem(long time, int size, int compressedSize) { 362 this.time = time; 363 this.size = size; 364 this.compressedSize = compressedSize; 365 } 366 } 367 } 368 | Popular Tags |