package org.jboss.jmx.adaptor.snmp.agent;
import gnu.regexp.RE;
import gnu.regexp.REException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.management.Notification;
import org.jboss.jmx.adaptor.snmp.config.notification.Mapping;
import org.jboss.jmx.adaptor.snmp.config.notification.VarBind;
import org.jboss.jmx.adaptor.snmp.config.notification.VarBindList;
import org.jboss.logging.Logger;
import org.jboss.xml.binding.ContentNavigator;
import org.jboss.xml.binding.GenericObjectModelFactory;
import org.jboss.xml.binding.ObjectModelFactory;
import org.jboss.xml.binding.Unmarshaller;
import org.opennms.protocols.snmp.SnmpPduPacket;
import org.opennms.protocols.snmp.SnmpPduRequest;
import org.opennms.protocols.snmp.SnmpPduTrap;
import org.xml.sax.Attributes;
public class TrapFactorySupport
implements TrapFactory
{
private static final Logger log = Logger.getLogger(TrapFactorySupport.class);
private SnmpVarBindFactory snmpVBFactory = null;
private String notificationMapResName = null;
private Clock clock = null;
private Counter trapCount = null;
private ArrayList notificationMapList = null;
private ArrayList mappingRegExpCache = null;
private ArrayList notificationWrapperCache = null;
public TrapFactorySupport()
{
this.snmpVBFactory = new SnmpVarBindFactory();
}
public void set(String notificationMapResName, Clock clock, Counter count)
{
this.notificationMapResName = notificationMapResName;
this.clock = clock;
this.trapCount = count;
}
public void start()
throws Exception
{
log.debug("Reading resource: '" + notificationMapResName + "'");
ObjectModelFactory omf = new NotificationBinding();
InputStream is = null;
try
{
is = this.getClass().getResourceAsStream(notificationMapResName);
Unmarshaller unmarshaller = new Unmarshaller();
this.notificationMapList = (ArrayList)unmarshaller.unmarshal(is, omf, null);
}
catch (Exception e)
{
log.error("Accessing resource '" + notificationMapResName + "'");
throw e;
}
finally
{
if (is != null)
{
is.close();
}
}
log.debug("Found " + notificationMapList.size() + " notification mappings");
this.mappingRegExpCache =
new ArrayList(notificationMapList.size());
this.notificationWrapperCache =
new ArrayList(notificationMapList.size());
for (Iterator i = notificationMapList.iterator(); i.hasNext(); )
{
Mapping mapping = (Mapping)i.next();
String notificationType = mapping.getNotificationType();
try
{
this.mappingRegExpCache.add(new RE(notificationType));
}
catch (REException e)
{
this.mappingRegExpCache.add(null);
log.warn("Error compiling notification mapping for type: " + notificationType, e);
}
String wrapperClassName = mapping.getVarBindList().getWrapperClass();
log.debug("notification wrapper class: " + wrapperClassName);
try
{
NotificationWrapper wrapper =
(NotificationWrapper)Class.forName(wrapperClassName, true, this.getClass().getClassLoader()).newInstance();
wrapper.set(this.clock, this.trapCount);
this.notificationWrapperCache.add(wrapper);
}
catch (Exception e)
{
this.notificationWrapperCache.add(null);
log.warn("Error compiling notification mapping for type: " + notificationType, e);
}
}
log.debug("Trap factory going active");
}
private int findMappingIndex(Notification n)
throws IndexOutOfBoundsException
{
for (int i = 0; i < notificationMapList.size(); i++)
{
RE p = (RE) this.mappingRegExpCache.get(i);
if (p != null)
{
if (p.isMatch(n.getType()))
{
if (log.isDebugEnabled())
log.debug("Match for '" + n.getType() + "' on mapping " + i);
return i;
}
}
}
throw new IndexOutOfBoundsException();
}
public SnmpPduTrap generateV1Trap(Notification n)
throws MappingFailedException
{
if (log.isDebugEnabled())
log.debug("generateV1Trap");
int index = -1;
try
{
index = findMappingIndex(n);
}
catch (IndexOutOfBoundsException e)
{
throw new MappingFailedException("No mapping found for notification type: '" +
n.getType() + "'");
}
Mapping m = (Mapping)this.notificationMapList.get(index);
SnmpPduTrap trapPdu = new SnmpPduTrap();
trapPdu.setTimeStamp(this.clock.uptime());
trapPdu.setGeneric(m.getGeneric());
trapPdu.setSpecific(m.getSpecific());
trapPdu.setEnterprise(m.getEnterprise());
NotificationWrapper wrapper =
(NotificationWrapper)this.notificationWrapperCache.get(index);
if(wrapper != null)
{
wrapper.prime(n);
List vbList = m.getVarBindList().getVarBindList();
for (int i = 0; i < vbList.size(); i++)
{
VarBind vb = (VarBind)vbList.get(i);
trapPdu.addVarBind(
this.snmpVBFactory.make(vb.getOid(), wrapper.get(vb.getTag())));
}
}
else
{
throw new MappingFailedException(
"Varbind mapping failure: null wrapper defined for " +
" notification type '" + m.getNotificationType() + "'" );
}
return trapPdu;
}
public SnmpPduPacket generateV2Trap(Notification n)
throws MappingFailedException
{
if (log.isDebugEnabled())
log.debug("generateV2Trap");
int index = -1;
try
{
index = findMappingIndex(n);
}
catch (IndexOutOfBoundsException e)
{
throw new MappingFailedException(
"No mapping found for notification type: '" + n.getType() + "'");
}
Mapping m = (Mapping)this.notificationMapList.get(index);
SnmpPduRequest trapPdu = new SnmpPduRequest(SnmpPduPacket.V2TRAP);
NotificationWrapper wrapper =
(NotificationWrapper)this.notificationWrapperCache.get(index);
if (wrapper != null)
{
wrapper.prime(n);
List vbList = m.getVarBindList().getVarBindList();
for (int i = 0; i < vbList.size(); i++)
{
VarBind vb = (VarBind)vbList.get(i);
trapPdu.addVarBind(
this.snmpVBFactory.make(vb.getOid(), wrapper.get(vb.getTag())));
}
}
else
{
log.warn("Varbind mapping failure: null wrapper defined for " +
" notification type '" + m.getNotificationType() + "'" );
}
return trapPdu;
}
private static class NotificationBinding implements GenericObjectModelFactory
{
public Object newRoot(Object root, ContentNavigator navigator, String namespaceURI,
String localName, Attributes attrs)
{
ArrayList notifList;
if (root == null)
{
root = notifList = new ArrayList();
}
else
{
notifList = (ArrayList) root;
}
return root;
}
public Object newChild(Object parent, ContentNavigator navigator, String namespaceURI,
String localName, Attributes attrs)
{
Object child = null;
if ("mapping".equals(localName))
{
Mapping m = new Mapping();
child = m;
}
else if ("var-bind-list".equals(localName))
{
VarBindList vblist = new VarBindList();
child = vblist;
if (attrs.getLength() > 0)
{
for (int i = 0; i < attrs.getLength(); i++)
{
if ("wrapper-class".equals(attrs.getLocalName(i)))
{
vblist.setWrapperClass(attrs.getValue(i));
}
}
}
if (vblist.getWrapperClass() == null)
{
throw new RuntimeException("'wrapper-class' must be set at 'var-bind-list' element");
}
}
else if ("var-bind".equals(localName))
{
VarBind vb = new VarBind();
child = vb;
}
return child;
}
public void addChild(Object parent, Object child, ContentNavigator navigator,
String namespaceURI, String localName)
{
if (parent instanceof ArrayList)
{
ArrayList notifList = (ArrayList)parent;
if (child instanceof Mapping)
{
notifList.add(child);
}
}
else if (parent instanceof Mapping)
{
Mapping m = (Mapping)parent;
if (child instanceof VarBindList)
{
m.setVarBindList((VarBindList)child);
}
}
else if (parent instanceof VarBindList)
{
VarBindList vblist = (VarBindList)parent;
if (child instanceof VarBind)
{
vblist.addVarBind((VarBind)child);
}
}
}
public void setValue(Object o, ContentNavigator navigator, String namespaceURI,
String localName, String value)
{
if (o instanceof Mapping)
{
Mapping m = (Mapping)o;
if ("notification-type".equals(localName))
{
m.setNotificationType(value);
}
else if ("generic".equals(localName))
{
m.setGeneric(Integer.parseInt(value));
}
else if ("specific".equals(localName))
{
m.setSpecific(Integer.parseInt(value));
}
else if ("enterprise".equals(localName))
{
m.setEnterprise(value);
}
}
else if (o instanceof VarBind)
{
VarBind vb = (VarBind)o;
if ("tag".equals(localName))
{
vb.setTag(value);
}
else if ("oid".equals(localName))
{
vb.setOid(value);
}
}
}
public Object completedRoot(Object root, ContentNavigator navigator, String namespaceURI, String localName)
{
return root;
}
}
}