www.pudn.com > sxg.rar > CacheHandler.java
/* * Copyright (c) 2003 Jens Mueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** Singleton class for caching of requested data in XML format. Cleans up cache periodically using inner classCachePurger, which forms an extra thread. @author Jens Mueller */ import java.io.PrintWriter; import java.util.List; import java.util.Iterator; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Attribute; import org.dom4j.Node; import org.dom4j.Branch; import org.dom4j.Namespace; import org.dom4j.XPath; import org.dom4j.io.XMLWriter; import org.dom4j.io.OutputFormat; public class CacheHandler { private static CacheHandler _instance; private Document _cache; private CachePurger _purger; private boolean _active; private Thread _thisThread; /** Cleans up cache periodically. The interval is determined by parametercachePurgeIntervalSecsin servlet's deployment descriptor. */ private class CachePurger implements Runnable { private long _sleepIntervalMillis; CachePurger( long interval ) { _sleepIntervalMillis = interval; _active = true; _thisThread = new Thread( this ); _thisThread.start(); } public void run() { while ( _active ) { try { _thisThread.sleep( _sleepIntervalMillis * 1000 ); } catch ( InterruptedException e ) { } purge(); } } public void stopExecution() { _active = false; } } private CacheHandler() { _cache = DocumentHelper.createDocument(); Element data = _cache.addElement( "cache" ); _purger = new CachePurger( GatewayConf.getCachePurgeIntervalSecs() ); } /** returns the running instance. If not instanciated yet, it constructs a newCacheHandler. */ private static CacheHandler getInstance() { if ( _instance == null ) _instance = new CacheHandler(); return _instance; } /** returns cached content, if up to date. If no content is found null is returned @param type the table- or scalargroup-type to be resolved from cache @param req the context / SNMP-Agent the content is cached for @return CacheRequestResult the result of resolving or null, if no content up to date is found */ public static synchronized CacheRequestResult getFromCache( GwComplexType type, ContextGetRequest req ) { CacheHandler handler = getInstance(); Node matchNode = get( type, req ); if ( matchNode != null ) { Element context = matchNode.getParent(); Attribute timeAttribute = context.attribute( GatewayConf.TIME ); if ( GwDate.timeDiff( GwDate.getCurrent(), timeAttribute.getValue() ) < ( GatewayConf.getCachingTimeSecs() * 1000 ) ) return new CacheRequestResult( timeAttribute.getValue(), context ); } return null; } /** iterates over cached content and removes data no longer up to date. periodically called byCachePurger*/ private static synchronized void purge() { CacheHandler handler = getInstance(); List elements = handler._cache.getRootElement().elements( "context" ); for ( Iterator iterator = elements.iterator(); iterator.hasNext(); ) { Element context = ( Element )iterator.next(); Attribute timeAttribute = context.attribute( GatewayConf.TIME ); if ( GwDate.timeDiff( GwDate.getCurrent(), timeAttribute.getValue() ) > ( GatewayConf.getCachingTimeSecs() * 1000 ) ) { detach( context ); } } } /** removes an XML-Element from cache. @param elem the Element to be removed */ private static synchronized void detach( Element elem ) { elem.detach(); } /** Adds content to the cache. @param type the table- or scalargroup-type to be added to cache @param req the context / SNMP-Agent the content is cached for */ public static synchronized void cacheIn( GwComplexType type, ContextGetRequest req ) { CacheHandler handler = getInstance(); detach( type, req ); handler._cache.getRootElement().appendContent( type.getTempDocument() ); } /** removes content from cache. Called after issuing of SNMP-set-requests. @param type the table- or scalargroup-type to be removed from cache @param req the context / SNMP-Agent the content is cached for */ public static synchronized void removeFromCache( GwComplexType type, ContextSetRequest req ) { CacheHandler handler = getInstance(); String PORT = GatewayConf.GET_PORT+"=\""+Integer.toString( req.getPort() ) + "\""; String IPADDR = GatewayConf.GET_IPADDR+"=\""+req.getIPaddr()+"\" and"; String HOSTNAME = GatewayConf.GET_HOSTNAME+"=\"" + req.getInetAddress().getCanonicalHostName()+"\" and"; XPath path = type.getTempDocument().createXPath("/cache/" + GatewayConf.GET_AGENTELEMENT+"["+ IPADDR + HOSTNAME + PORT +"]/"+type.getName()); Node node = path.selectSingleNode( handler._cache ); if( node != null ) { detach( node.getParent() ); } } /** removes content from cache. @param type the table- or scalargroup-type to be removed from cache @param req the context / SNMP-Agent the content is cached for */ private static synchronized void detach( GwComplexType type, ContextGetRequest req ) { CacheHandler handler = getInstance(); Node matchNode = get( type, req ); if ( matchNode != null ) { //Element context = get( type, req ).getParent(); //detach( context ); detach( matchNode.getParent() ); } } /** searches for cached content and returns the XML-Node if found. @param type the table- or scalargroup-type to be resolved from cache @param req the context / SNMP-Agent the content is cached for @return Node the XML-Node of the content, null if no content is found */ private static synchronized Node get( GwComplexType type, ContextGetRequest req ) { CacheHandler handler = getInstance(); String PORT = GatewayConf.GET_PORT+"=\""+Integer.toString( req.getPort() ) + "\" and"; String COMMSTRING = GatewayConf.GET_COMM_STR+"=\""+req.getCommString()+ "\""; String IPADDR = GatewayConf.GET_IPADDR+"=\""+req.getIPaddr()+"\" and"; String HOSTNAME = GatewayConf.GET_HOSTNAME+"=\"" + req.getInetAddress().getCanonicalHostName()+"\" and"; XPath path = type.getTempDocument().createXPath("/cache/" + GatewayConf.GET_AGENTELEMENT+"["+ IPADDR + HOSTNAME + PORT + COMMSTRING +"]/"+type.getName()); Node node = path.selectSingleNode( handler._cache ); if ( node != null ) return node; else return null; } /** writes textual representation of cached content towriterfor debugging */ public static void dump( PrintWriter writer ) { OutputFormat outputformat = new OutputFormat( " ", true ); XMLWriter xmlWriter = new XMLWriter( writer, outputformat ); try {xmlWriter.write( getInstance()._cache );} catch (Throwable th) {}; } }