com.davfx.ninio.snmp.SnmpCache Maven / Gradle / Ivy
package com.davfx.ninio.snmp;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.davfx.ninio.core.Address;
import com.davfx.ninio.core.Queue;
import com.davfx.ninio.core.ReadyFactory;
import com.davfx.util.DateUtils;
public final class SnmpCache {
private static final Logger LOGGER = LoggerFactory.getLogger(SnmpCache.class);
public static interface Filter {
double cache(Address address, Oid oid);
}
// Memory saving!
private final Map internOids = new HashMap<>();
private final Map internStrings = new HashMap<>();
private Oid internOid(Oid oid) {
Oid intern = internOids.get(oid);
if (intern == null) {
intern = oid;
internOids.put(intern, intern);
}
return intern;
}
private String internString(String s) {
String intern = internStrings.get(s);
if (intern == null) {
intern = s;
internStrings.put(intern, intern);
}
return intern;
}
private Result internResult(Result result) {
return new Result(internOid(result.getOid()), internString(result.getValue()));
}
private static final class DataCacheElement {
public final List results = new LinkedList<>();
public List callbacks = new LinkedList<>();
public final double timestamp;
public DataCacheElement(double timestamp) {
this.timestamp = timestamp;
}
}
private static final class CacheElement {
public IOException ioe = null;
public double timestamp;
public final Map data = new HashMap<>();
public CacheElement() {
}
}
private final Map cache = new HashMap<>();
private final Queue queue;
private final ReadyFactory readyFactory;
private final Filter filter;
public SnmpCache(Queue queue, ReadyFactory readyFactory, Filter filter) {
this.queue = queue;
this.readyFactory = readyFactory;
this.filter = filter;
}
// May be called often to save memory
public void clear() {
Iterator i = cache.values().iterator();
while (i.hasNext()) {
CacheElement g = i.next();
Iterator j = g.data.values().iterator();
while (j.hasNext()) {
DataCacheElement e = j.next();
if (e.callbacks == null) {
j.remove();
}
}
if (g.data.isEmpty()) {
i.remove();
}
}
}
public void get(final Address address, final Oid oid, final SnmpClientHandler.Callback.GetCallback getCallback) {
final double delayToDiscard = filter.cache(address, oid);
if (Double.isNaN(delayToDiscard)) {
LOGGER.trace("Not caching {}", oid);
new Snmp().override(readyFactory).withQueue(queue).to(address).get(oid, getCallback);
return;
}
queue.post(new Runnable() {
@Override
public void run() {
double now = DateUtils.now();
CacheElement f = cache.get(address);
if (f == null) {
f = new CacheElement();
cache.put(address, f);
}
if (f.ioe != null) {
if ((now - f.timestamp) > delayToDiscard) {
f.ioe = null;
}
}
if (f.ioe != null) {
getCallback.failed(f.ioe);
return;
}
DataCacheElement e = f.data.get(oid);
if (e != null) {
if (e.callbacks == null) {
if ((now - e.timestamp) > delayToDiscard) {
e = null;
}
}
}
if (e == null) {
e = new DataCacheElement(now);
f.data.put(oid, e);
}
if (e.callbacks == null) {
for (Result r : e.results) {
getCallback.result(r);
}
getCallback.close();
} else {
if (e.callbacks.isEmpty()) {
e.callbacks.add(getCallback);
call(address, oid, e, f);
} else {
e.callbacks.add(getCallback);
}
}
}
});
}
private void call(final Address address, Oid oid, final DataCacheElement e, final CacheElement f) {
LOGGER.trace("Actually calling {}", oid);
new Snmp().override(readyFactory).withQueue(queue).to(address).get(oid, new SnmpClientHandler.Callback.GetCallback() {
@Override
public void failed(IOException ioe) {
f.ioe = ioe;
f.timestamp = DateUtils.now();
for (SnmpClientHandler.Callback.GetCallback c : e.callbacks) {
c.failed(ioe);
}
e.callbacks = null;
}
@Override
public void close() {
for (SnmpClientHandler.Callback.GetCallback c : e.callbacks) {
c.close();
}
e.callbacks = null;
}
@Override
public void result(Result result) {
double now = DateUtils.now();
Result internResult = internResult(result);
Oid oid = internOid(result.getOid());
final double delayToDiscard = filter.cache(address, oid);
if (!Double.isNaN(delayToDiscard)) {
// Cache single value
DataCacheElement r = f.data.get(oid);
if (r != null) {
if (r.callbacks == null) {
if ((now - r.timestamp) > delayToDiscard) {
r = null;
}
}
}
if (r == null) {
r = new DataCacheElement(e.timestamp);
LOGGER.trace("Caching single value: {} = {}", oid, result);
f.data.put(oid, r);
r.results.add(internResult);
r.callbacks = null;
}
}
e.results.add(internResult);
for (SnmpClientHandler.Callback.GetCallback c : e.callbacks) {
c.result(result);
}
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy