/* * 'SNMPSessionCache.java' NOTE: This copyright does *not* cover user programs * that use HQ program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development Kit or * the Hyperic Client Development Kit - this is merely considered normal use of * the program, and does *not* fall under the heading of "derived work". * Copyright (C) [2004, 2005, 2006, 2007, 2008, 2009], Hyperic, Inc. This file * is part of HQ. HQ is free software; you can redistribute it and/or modify it * under the terms version 2 of the GNU General Public License as published by * the Free Software Foundation. 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; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.snmp; import java.util.HashMap; import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.util.timer.StopWatch; /* * SNMPSession interface cache. Cache is per-session instance. Currently * supports getColumn and getBulk methods only. */ class SNMPSessionCache implements InvocationHandler { private SNMPSession session; private HashMap columnCache = new HashMap(); private HashMap bulkCache = new HashMap(); private HashMap tableCache = new HashMap(); private static Log log = LogFactory.getLog(SNMPSessionCache.class); public static final int EXPIRE_DEFAULT = 30 * 1000; // 30 seconds private int expire; SNMPSessionCache(SNMPSession session, int expire) { this.session = session; this.expire = expire; } static SNMPSession newInstance(SNMPSession session, int expire) throws SNMPException { SNMPSessionCache handler = new SNMPSessionCache(session, expire); SNMPSession sessionCache; try { sessionCache = (SNMPSession) Proxy.newProxyInstance(SNMPSession.class.getClassLoader(), new Class[] { SNMPSession.class }, handler); } catch (Exception e) { throw new SNMPException(e.getMessage()); } return sessionCache; } private SNMPCacheObject getFromCache(long timeNow, HashMap cache, String name, Object arg) { SNMPCacheObject cacheVal = (SNMPCacheObject) cache.get(arg); String argDebug = ""; if (log.isDebugEnabled()) { argDebug = " with arg=" + arg; } if (cacheVal == null) { cacheVal = new SNMPCacheObject(); cacheVal.expire = this.expire; cache.put(arg, cacheVal); } else if ((timeNow - cacheVal.timestamp) > cacheVal.expire) { if (log.isDebugEnabled()) { log.debug("expiring " + name + " from cache" + argDebug); } cacheVal.value = null; } return cacheVal; } private StringBuffer invokerToString(String name, Object[] args, Object cacheKey) { StringBuffer invoker = new StringBuffer(name); invoker.append('('); if (args.length != 0) { String arg = args[0].toString(); invoker.append(arg); for (int i = 1; i < args.length; i++) { invoker.append('.').append(args[i].toString()); } if ((cacheKey != null) && !arg.toString().equals(cacheKey)) { // Note real cache key to match up with expire log... invoker.append('/').append(cacheKey.toString()); } invoker.append(')'); } return invoker; } public Object invoke(Object proxy, Method method, Object[] args) throws SNMPException { SNMPCacheObject cacheVal = null; HashMap cache = null; Object cacheKey = null; Object retval; String name = method.getName(); long timeNow = 0; // Perhaps more later... if (name.equals("getBulk")) { cache = this.bulkCache; cacheKey = args[0]; } else if (name.equals("getTable")) { cache = this.tableCache; cacheKey = new Integer(args[0].hashCode() ^ args[1].hashCode()); } else if (name.equals("getColumn")) { cache = this.columnCache; cacheKey = args[0]; } if (cache != null) { timeNow = System.currentTimeMillis(); cacheVal = getFromCache(timeNow, cache, name, cacheKey); if (cacheVal.value != null) { return cacheVal.value; } } try { retval = method.invoke(this.session, args); } catch (InvocationTargetException e) { Throwable t = ((InvocationTargetException) e).getTargetException(); String msg; if (t instanceof MIBLookupException) { throw (MIBLookupException) t; } if (t instanceof SNMPException) { msg = ""; } else { msg = t.getClass().getName() + ": "; } msg += t.getMessage() + " invoking: " + invokerToString(name, args, cacheKey); throw new SNMPException(msg, t); } catch (Exception e) { String msg = e.getClass().getName() + ": " + e.getMessage() + " invoking: " + invokerToString(name, args, cacheKey); throw new SNMPException(msg, e); } if (cacheVal != null) { cacheVal.value = retval; cacheVal.timestamp = timeNow; if (log.isDebugEnabled()) { log.debug(invokerToString(name, args, cacheKey) + " took: " + new StopWatch(timeNow)); } } return retval; } }