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: }