/* * Copyright 2013 The Http Server & Proxy * * The Http Server & Proxy Project licenses this file to you 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.sohail.alam.http.common.smartcache; import com.sohail.alam.http.common.watchservice.WatchService; import com.sohail.alam.http.common.watchservice.WatchServiceCallback; import com.sohail.alam.http.common.watchservice.WatchServiceException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import static com.sohail.alam.http.common.LoggerManager.LOGGER; /** * User: Sohail Alam * Version: 1.0.0 * Date: 25/9/13 * Time: 8:56 PM */ public class SmartCache<T extends SmartCachePojo> { private final Map<String, T> CACHE = new ConcurrentHashMap<String, T>(); private final WatchService WATCH_SERVICE; public AtomicLong cacheSizeInBytes; private SmartCache() { LOGGER.trace("Smart Cache initialized"); cacheSizeInBytes = new AtomicLong(0); WATCH_SERVICE = WatchService.watcher(); try { WATCH_SERVICE.addCallbackListener(new FileWatchServiceCallback()); } catch (WatchServiceException e) { LOGGER.debug("Error Adding File Watch Service Callback", e); } } public static SmartCache cache() { return SingletonHolder.INSTANCE; } public long size() { return CACHE.size(); } public void put(String absFileName, T data) { if (CACHE.get(absFileName) == null) { CACHE.put(absFileName, data); cacheSizeInBytes.set(cacheSizeInBytes.get() + data.fileSize); LOGGER.debug("Data of Size: {}, Last Modified: {}, added to Smart Cache => {}", data.fileSize, data.lastModified, absFileName); WATCH_SERVICE.watch(data.file); } } public T get(String absFileName) { return CACHE.get(absFileName); } public T remove(String absFileName) { if (CACHE.get(absFileName) != null) { T data = CACHE.remove(absFileName); cacheSizeInBytes.set(cacheSizeInBytes.get() - data.fileSize); LOGGER.debug("Data of Size: {}, Last Modified: {}, removed from Smart Cache => {}", data.fileSize, data.lastModified, absFileName); return data; } return null; } private interface SingletonHolder { public static final SmartCache INSTANCE = new SmartCache(); } /** * The type File watch service callback. */ private class FileWatchServiceCallback implements WatchServiceCallback.FileService { /** * File modified. * * @param file the file * @param oldLastModified the old last modified * @param newLastModified the new last modified */ @Override public void fileModified(File file, long oldLastModified, long newLastModified) { LOGGER.debug("File {} was modified", file.getAbsoluteFile()); T pojo = CACHE.get(file.getAbsolutePath()); try { FileInputStream is = new FileInputStream(file); pojo.fileData = new byte[is.available()]; pojo.fileSize = is.read(pojo.fileData); pojo.lastModified = newLastModified; CACHE.put(file.getAbsolutePath(), pojo); cacheSizeInBytes.set(cacheSizeInBytes.get() + pojo.fileSize); LOGGER.debug("Data of Size: {}, Last Modified: {}, updated into Smart Cache => {}", pojo.fileSize, pojo.lastModified, file.getAbsolutePath()); } catch (FileNotFoundException e) { } catch (IOException e) { } } /** * File no longer exists. * * @param file the file * @param lastModified the last modified */ @Override public void fileNoLongerExists(File file, long lastModified) { LOGGER.debug("File {} no longer exists", file.getAbsoluteFile()); SmartCache.cache().remove(file.getAbsolutePath()); } /** * Exception caught. * * @param file the file * @param cause the cause */ @Override public void exceptionCaught(File file, Throwable cause) { LOGGER.debug("Exception Caught in FileWatchServiceCallback: ", cause); } /** * Already watching file. * * @param file the file */ @Override public void alreadyWatchingFile(File file) { // ignored } } }