/*
* '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;
}
}