package at.ac.ait.ubicity.fileloader.util; /** Copyright (C) 2013 AIT / Austrian Institute of Technology http://www.ait.ac.at This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/agpl-3.0.html */ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * Default implementation of the FileCache interface. * @author jan van oort */ public final class LogFileCache implements FileCache, Serializable { /** Name of the default cache file */ protected static final String DEFAULT_CACHE_FILE = "monitrix.logfile.cache"; final static Logger logger = Logger.getLogger( LogFileCache.class.getName() ); /** Is the cache enabled ? */ protected boolean cacheEnabled = true; /** maps a URI to a FileInformation object */ protected Map< URI, FileInformation > cacheMap; protected boolean weakMode = false; /* an alternative place for the cache file */ protected String cachePath = DEFAULT_CACHE_FILE; /* a singleton; in principle,we only ever need one instance */ private final static FileCache singleton; /** * make sure the singleton is always there */ static { logger.setLevel( Level.ALL ); singleton = new LogFileCache(); } //here for the singleton pattern private LogFileCache() { cacheMap = new HashMap(); } /** * * @return FileCache - our singleton */ public static final FileCache get() { return singleton; } /** * * @param _uri The key: a URI ( of a file or directory ) we wish to save / cache information for * @param _info The value: a FileInformation object we cache with this URI key * @return this same FileCache ( "convention over configuration"-like stuff ) */ @Override public final FileCache updateCacheFor( URI _uri, FileInformation _info ) { logger.fine("updating cache for uri " + _uri.toASCIIString() ); cacheMap.put(_uri, _info ); return this; } @Override public final FileInformation getFileInformationFor( final URI uri ) { logger.finer("cache request for uri: " + uri.toASCIIString() ); return cacheMap.get( uri ); } /** * * @return this FileCache; if enabled, its cache map will have been filled; * an empty cache map is carried otherwise. * * We always return a FileCache, in a best effort to provide the caller with this utility. * The caller is supposed to know how, whether or not to use this class. */ @Override public FileCache loadCache() { if ( ! cacheEnabled ) { return this; } final String cacheFile = (this.cachePath == null) ? DEFAULT_CACHE_FILE : this.cachePath; try { final FileInputStream fis = new FileInputStream( cacheFile ); final Object rval; ObjectInputStream ois = new ObjectInputStream( fis ); rval = ois.readObject(); if (rval != null) { cacheMap = ( Map< URI, FileInformation >) rval; } } catch( final NullPointerException | FileNotFoundException npe ) { logger.info( "no cache file was found at " + ( (this.cachePath == null) ? DEFAULT_CACHE_FILE : this.cachePath ) + "; starting with a fresh, empty cache" ); } catch (final ClassNotFoundException e) { logger.warning("Your cache is outdated, please delete it. It will be regenerated with the next run. The next exception reflects this, so don't be afraid."); } catch (final IOException e1) { logger.severe("caught an IOException while trying to load cache : IOException : " + e1); } finally { return this; } } /** * * @return this FileCache, which has undergone no state changes. */ @Override public FileCache saveCache() { if (!this.cacheEnabled) { return this; } String cacheFile = this.cachePath; FileOutputStream fos = null; ObjectOutputStream oos = null; if (cacheFile == null) { cacheFile = DEFAULT_CACHE_FILE; } try { fos = new FileOutputStream(cacheFile); oos = new ObjectOutputStream(fos); oos.writeObject(this.cacheMap); oos.flush(); logger.info( "saved cache files @" + this.cachePath ); } catch (final FileNotFoundException e) { logger.severe( "cache file creation problem : " + e.toString() ); } catch (final IOException e) { logger.warning( "an I/O exception was caught while saving the log file cache : " + e.toString() ); } finally { try { oos.close(); fos.close(); } catch (Exception e) { //swallow this one, we're not gonna do anything with it, the next step is to brutally <null> our resources and carry on } finally { oos = null; fos = null; logger.info( "persisted the cache to " + ( new File( cacheFile ) ).toURI() ); return this; } } } @Override public void setCachePath( final String _cachePath ) { cachePath = _cachePath; } @Override public void setEnabled( final boolean u ) { cacheEnabled = u; } /** * * @param w -- boolean: should we function in weak mode or not ? * NOTE: this functionality is currently not implemented / used. */ @Override public void setWeakMode( final boolean w ) { weakMode = w; } }