tim@845: /**
tim@845:  *
tim@845:  */
tim@845: package de.intevation.gnv.state.cache;
tim@845: 
tim@845: import java.util.ArrayList;
tim@845: import java.util.Collection;
tim@845: import java.util.Iterator;
tim@845: import java.util.List;
tim@845: 
tim@845: import net.sf.ehcache.Cache;
tim@845: 
tim@845: import org.apache.log4j.Logger;
tim@845: import org.w3c.dom.Document;
tim@845: import org.w3c.dom.Element;
tim@845: import org.w3c.dom.NodeList;
tim@845: 
tim@845: import de.intevation.artifactdatabase.Config;
tim@845: import de.intevation.gnv.artifacts.cache.CacheFactory;
tim@845: import de.intevation.gnv.geobackend.base.query.cache.CacheCleaner;
tim@845: import de.intevation.gnv.geobackend.base.query.container.QueryContainerFactory;
tim@845: import de.intevation.gnv.geobackend.base.query.container.exception.QueryContainerException;
tim@845: import de.intevation.gnv.geobackend.base.query.exception.QueryException;
tim@845: import de.intevation.gnv.state.StateBase;
tim@845: import de.intevation.gnv.utils.ArtifactXMLUtilities;
tim@845: 
tim@845: 
tim@845: /**
tim@845:  * Extended Class of the CacheCleaner.
tim@845:  * This Cleaner has the job to cleanup the ThematicData-Cache if it
tim@845:  * is necessary.
tim@845:  * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
tim@845:  *
tim@845:  */
tim@845: public class ThematicDataCacheCleaner extends CacheCleaner {
tim@845: 
tim@845:     /**
tim@845:      * the logger, used to log exceptions and additonaly information
tim@845:      */
tim@845:     private static Logger log = Logger.getLogger(ThematicDataCacheCleaner.class);
tim@845:     
tim@845:     private final static String XPATH_ARTIFACTS = 
tim@845:                                     "/artifact-database/artifacts/artifact";
tim@845:     private final static String XPATH_STATES = "states/state";
tim@845:     private final static String XPATH_STATEID = "id";
tim@845:     private final static String XPATH_QUERYID = "queryID";
tim@845: 
tim@845:     /**
tim@845:      * The Queries that should be Cleaned with its links to the
tim@845:      * StateIds.
tim@845:      */
tim@845:     private Collection<QueryObject> queryObjects = null;
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      */
tim@845:     public ThematicDataCacheCleaner() {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(Runnable arg0) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(String arg0) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      * @param arg1
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(ThreadGroup arg0, Runnable arg1) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      * @param arg1
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(ThreadGroup arg0, String arg1) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      * @param arg1
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(Runnable arg0, String arg1) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      * @param arg1
tim@845:      * @param arg2
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(ThreadGroup arg0, Runnable arg1, String arg2) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Constructor
tim@845:      * @param arg0
tim@845:      * @param arg1
tim@845:      * @param arg2
tim@845:      * @param arg3
tim@845:      */
tim@845:     public ThematicDataCacheCleaner(ThreadGroup arg0, Runnable arg1,
tim@845:                                     String arg2, long arg3) {
tim@845:         this.setUp();
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Initializes the QueryObjects.
tim@845:      * The Queryobjects will be read from the Configuration.
tim@845:      * Only Queries which are defined in <code>queryID</code>-Elements
tim@845:      * are used.
tim@845:      * The other Queries are currently not put into the Cache.
tim@845:      */
tim@845:     @Override
tim@845:     protected void setUp(){
tim@845:         super.setUp();
tim@845:         this.queryObjects = new ArrayList<QueryObject>();
tim@845:         Document configuration = Config.getConfig();
tim@845:         NodeList artifactList = Config.getNodeSetXPath(configuration,
tim@845:                                                        XPATH_ARTIFACTS);
tim@845:         log.debug("ThematicDataCacheCleaner.setUp()");
tim@845:         if (artifactList != null && artifactList.getLength() > 0){
tim@845:             for (int i = 0; i < artifactList.getLength(); i++){
tim@845:                 Element currentArtifactNode = (Element)artifactList.item(i);
tim@845:                 
tim@845:                 String link = currentArtifactNode.getAttribute("xlink:href");
tim@845:                 if (link != null && link.length() > 0){
tim@845:                     String absolutFileName = Config.replaceConfigDir(link);
tim@845:                     currentArtifactNode = (Element)new ArtifactXMLUtilities()
tim@845:                                            .readConfiguration(absolutFileName);
tim@845:                 }
tim@845:                 NodeList stateList = Config.getNodeSetXPath(currentArtifactNode,
tim@845:                                                             XPATH_STATES);
tim@845:                 if (stateList != null && stateList.getLength() > 0){
tim@845:                     for (int j = 0; j < stateList.getLength() ; j++){
tim@845:                         Element currentStateNode = (Element)stateList.item(j);
tim@845:                         String stateId = currentStateNode
tim@845:                                           .getAttribute(XPATH_STATEID);
tim@845:                         String queryID = Config.getStringXPath(currentStateNode, 
tim@845:                                                                 XPATH_QUERYID);
tim@845:                         try {
tim@845:                             if (queryID != null){
tim@845:                                 String query = QueryContainerFactory
tim@845:                                                     .getInstance()
tim@845:                                                     .getQueryContainer()
tim@845:                                                     .getQuery(queryID);
tim@845:                                 QueryObject qo = new QueryObject(stateId, query);
tim@845:                                 queryObjects.add(qo);
tim@845:                             }
tim@845:                         } catch (QueryContainerException e) {
tim@845:                             log.error(e,e);
tim@845:                         }
tim@845:                     }
tim@845:                 }
tim@845:             }
tim@845:         }
tim@845:     }
tim@845: 
tim@845:     @Override
tim@845:     protected void cleanup() {
tim@845:         log.debug("ThematicDataCacheCleaner.cleanup");
tim@845:         try {
tim@845:             if (queryObjects != null && queryObjects.size() > 0){
tim@845:                 String[] tableNames = this.getUpdatedTableNames();
tim@845:                 if (tableNames != null && tableNames.length > 0){
tim@845:                     Iterator<QueryObject> it = queryObjects.iterator();
tim@845:                     while (it.hasNext()){
tim@845:                         QueryObject qo = it.next();
tim@845:                         for (int i = 0; i < tableNames.length; i++){
tim@845:                             if (qo.queryContainsTableName(tableNames[i])){
tim@845:                                 String stateId = qo.getStateId();
tim@845:                                 this.cleanUpCache(stateId);
tim@845:                                 break;
tim@845:                             }
tim@845:                         }
tim@845:                     }
tim@845:                 }else{
tim@845:                     log.debug("No Tables found to cleanup.");
tim@845:                 }
tim@845:             }else{
tim@845:                 log.warn("No Queries to clean");
tim@845:             }
tim@845:         } catch (QueryException e) {
tim@845:             log.error(e,e);
tim@845:         }
tim@845:     }
tim@845: 
tim@845:     /**
tim@845:      * Removes the Entries which Keys matches to the <code>stateId</code>
tim@845:      * from the Cache.
tim@845:      * @param stateId The Id of the State which Entries has to be removed.
tim@845:      */
tim@845:     private void cleanUpCache(String stateId){
tim@845:         log.debug("ThematicDataCacheCleaner.cleanUpCache "+stateId);
tim@845:         CacheFactory factory = CacheFactory.getInstance();
tim@845:         Cache cache = factory.getCache();
tim@845:         List<String> keys = cache.getKeys();
tim@845:         String keySample = StateBase.HASH_ID_SEPARATOR +
tim@845:                      stateId + 
tim@845:                      StateBase.HASH_ID_SEPARATOR;
tim@845:         if (keys != null && keys.size() > 0){
tim@845:             Iterator<String> it = keys.iterator();
tim@845:             while (it.hasNext()){
tim@845:                 String key = it.next();
tim@845:                 if (key != null && key.contains(keySample)){
tim@845:                     boolean removed = cache.remove(key);
tim@845:                     if (!removed){
tim@845:                         log.warn("Object with Key " + 
tim@845:                                  key + "could not be removed from Cache");
tim@845:                     }else{
tim@845:                         log.debug("Object with Key " + 
tim@845:                                  key + "has been removed from Cache");
tim@845:                     }
tim@845:                 }
tim@845:             }
tim@845:         }
tim@845:     }
tim@845: }