ingo@1127: /* ingo@1127: * Copyright (c) 2010 by Intevation GmbH ingo@1127: * ingo@1127: * This program is free software under the LGPL (>=v2.1) ingo@1127: * Read the file LGPL.txt coming with the software for details ingo@1127: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1127: */ ingo@1127: tim@895: /** tim@895: * tim@895: */ tim@895: package de.intevation.gnv.geobackend.base.query.cache; tim@895: tim@895: import java.sql.Date; tim@895: import java.util.Collection; tim@895: import java.util.Iterator; tim@895: tim@895: import org.apache.log4j.Logger; tim@895: tim@895: import de.intevation.gnv.geobackend.base.Result; tim@895: import de.intevation.gnv.geobackend.base.query.DefaultQueryExceutor; tim@895: import de.intevation.gnv.geobackend.base.query.QueryExecutor; tim@895: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; tim@895: import de.intevation.gnv.geobackend.base.query.exception.QueryException; tim@895: import de.intevation.gnv.geobackend.util.DateUtils; tim@895: tim@895: /** tim@895: * Thread that looks every n - Minutes if an Cache has to be cleanedup. tim@895: * You can configure the Timeout in Seconds using the Systemproperty tim@895: * @author Tim Englich tim@895: * tim@895: */ tim@895: public class CacheCleaner extends Thread { tim@895: tim@895: /** tim@895: * the logger, used to log exceptions and additonaly information tim@895: */ tim@895: private static Logger log = Logger.getLogger(CacheCleaner.class); tim@895: tim@895: /** tim@895: * The Systemproperty-identifier for the Configuration of the TimeInterval tim@895: */ tim@895: public static final String CACHE_CLEANER_INTERVAL = "caching.cleaner.interval"; ingo@897: tim@895: /** tim@895: * The Time To wait between two Cleanups. tim@895: */ tim@895: private long timeout = 1000 * 60; // 1 Minute ingo@897: tim@895: /** tim@895: * The Border which has to be used to Query the updated Tables. tim@895: */ tim@895: private long lowerBorderTime = 0; tim@895: tim@895: /** tim@895: * The Id to Lookup the SQL-Statement for fetchung the Names of the tim@895: * updated Tables. tim@895: */ tim@895: private String queryID = "updated_tables"; tim@895: tim@895: /** tim@895: * Constructor tim@895: */ tim@895: public CacheCleaner() { tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: */ tim@895: public CacheCleaner(Runnable arg0) { tim@895: super(arg0); tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: */ tim@895: public CacheCleaner(String arg0) { tim@895: super(arg0); tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: * @param arg1 tim@895: */ tim@895: public CacheCleaner(ThreadGroup arg0, Runnable arg1) { tim@895: super(arg0, arg1); tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: * @param arg1 tim@895: */ tim@895: public CacheCleaner(ThreadGroup arg0, String arg1) { tim@895: super(arg0, arg1); tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: * @param arg1 tim@895: */ tim@895: public CacheCleaner(Runnable arg0, String arg1) { tim@895: super(arg0, arg1); tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: * @param arg1 tim@895: * @param arg2 tim@895: */ tim@895: public CacheCleaner(ThreadGroup arg0, Runnable arg1, String arg2) { tim@895: super(arg0, arg1, arg2); tim@895: this.setUp(); tim@895: } tim@895: tim@895: /** tim@895: * Constructor tim@895: * @param arg0 tim@895: * @param arg1 tim@895: * @param arg2 tim@895: * @param arg3 tim@895: */ tim@895: public CacheCleaner(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) { tim@895: super(arg0, arg1, arg2, arg3); tim@895: this.setUp(); tim@895: } ingo@897: tim@895: /** tim@895: * Sets up the members of the CacheCleaner. tim@895: */ tim@895: protected void setUp(){ tim@895: String intervalValue = System.getProperty(CACHE_CLEANER_INTERVAL); tim@895: if (intervalValue != null){ tim@895: log.info("Set Interval to "+intervalValue+" Seconds"); tim@895: try { tim@895: this.timeout = Long.parseLong(intervalValue) * 1000; tim@895: } catch (NumberFormatException e) { tim@895: log.error(e,e); tim@895: } tim@895: } tim@895: } tim@895: tim@895: /** tim@895: * This Method can be used do run the Main-Mechanism of the Thread e.g tim@895: * from a Unittest. tim@895: * @return tim@895: */ tim@895: public boolean test(){ tim@895: log.debug("CacheCleaner.test"); tim@895: this.cleanup(); tim@895: return true; tim@895: } tim@895: tim@895: @Override tim@895: public void run() { tim@895: log.debug("CacheCleaner.run"); tim@895: long requiredTime = 0; tim@895: this.lowerBorderTime = System.currentTimeMillis(); tim@895: while (true){ tim@895: long startTime = 0; tim@895: try { tim@895: long nextTimeout = timeout-requiredTime; tim@895: if (nextTimeout > 0){ tim@895: Thread.sleep(nextTimeout); tim@895: } tim@895: startTime = System.currentTimeMillis(); tim@895: log.debug("Sleep "+nextTimeout+"ms cleanup Cache now"); tim@895: this.cleanup(); tim@895: } catch (InterruptedException e) { tim@895: log.error(e,e); tim@895: } catch (Exception e){ tim@895: log.error(e,e); tim@895: } catch (Throwable t){ tim@895: log.error(t,t); tim@895: }finally{ tim@895: requiredTime = System.currentTimeMillis() - startTime; tim@895: log.debug("CleanUp required "+requiredTime); tim@895: } tim@895: } tim@895: } tim@895: tim@895: /** tim@895: * Method that do the Cleanup-Work tim@895: */ tim@895: protected void cleanup(){ tim@895: log.debug("CacheCleaner.cleanup"); tim@895: try { tim@895: // We have to go this Way to avoid using the Cache for this Query. tim@895: String[] tableNames = this.getUpdatedTableNames(); tim@895: if (tableNames != null){ tim@895: QueryExecutorFactory.getInstance() tim@895: .getQueryExecutor().clearCache(tableNames); tim@895: } tim@895: } catch (QueryException e) { tim@895: log.error(e,e); tim@895: } ingo@897: tim@895: } tim@895: tim@895: /** tim@895: * Returns the Names of the Tables which have been updated. tim@895: * @return the Names of the Tables which have been updated. tim@895: * @throws QueryException tim@895: */ tim@895: protected String[] getUpdatedTableNames()throws QueryException { tim@895: String[] tableNames = null; tim@895: QueryExecutor queryExecutor = new DefaultQueryExceutor(); tim@895: Date date = new Date(this.lowerBorderTime); tim@895: this.lowerBorderTime = System.currentTimeMillis(); tim@895: log.debug("New Lookup at "+DateUtils.getPatternedDateAmer(new Date(lowerBorderTime))); tim@895: String queryDate = DateUtils.getPatternedDateAmer(date); tim@895: Collection result = queryExecutor. ingo@897: executeQuery(queryID, tim@895: new String[]{queryDate}); tim@895: if (result != null && !result.isEmpty()){ tim@895: tableNames = new String[result.size()]; tim@895: Iterator it = result.iterator(); tim@895: int i = 0; tim@895: while (it.hasNext()){ tim@895: tableNames[i++] = it.next().getString(0).toUpperCase(); tim@895: log.debug("Table that was updated: "+tableNames[i-1]); tim@895: } tim@895: } tim@895: return tableNames; tim@895: } tim@895: }