/* * Copyright (c) 2003, Intracom S.A. - www.intracom.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * This package and its source code is available at www.jboss.org */ package org.jboss.jmx.adaptor.snmp.agent; import java.net.InetAddress; import java.net.UnknownHostException; import javax.management.Notification; import javax.management.ObjectName; import org.jboss.bootstrap.spi.ServerConfig; import org.jboss.system.ListenerServiceMBeanSupport; import org.opennms.protocols.snmp.SnmpAgentSession; import org.opennms.protocols.snmp.SnmpPeer; import org.opennms.protocols.snmp.SnmpSMI; /** * <tt>SnmpAgentService</tt> is an MBean class implementing an SNMP agent. * * It allows to send V1 or V2 traps to one or more SNMP managers defined * by their IP address, listening port number and expected SNMP version. * * It support mapping SNMP get/set requests JMX mbean attribute get/sets. * * @jmx:mbean * extends="org.jboss.system.ListenerServiceMBean" * * @author <a href="mailto:spol@intracom.gr">Spyros Pollatos</a> * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a> * @author <a href="mailto:krishnaraj@ieee.org">Krishnaraj S</a> * @version $Revision: 80636 $ */ public class SnmpAgentService extends ListenerServiceMBeanSupport implements SnmpAgentServiceMBean { /** Supported versions */ public static final int SNMPV1 = 1; public static final int SNMPV2 = 2; /** Default communities */ public static final String DEFAULT_READ_COMMUNITY = "public"; public static final String DEFAULT_WRITE_COMMUNITY = "private"; // Private data -------------------------------------------------- /** Time keeping*/ private Clock clock = null; /** Trap counter */ private Counter trapCounter = null; /** Name of the file containing SNMP manager specifications */ private String managersResName = null; /** Name of resource file containing notification to trap mappings */ private String notificationMapResName = null; /** Name of resource file containing get/set mappings */ private String requestHandlerResName = null; /** Name of the trap factory class to be utilised */ private String trapFactoryClassName = null; /** Name of request handler implementation class */ private String requestHandlerClassName = null; /** The SNMP read community to use */ private String readCommunity = DEFAULT_READ_COMMUNITY; /** The SNMP write community to use */ private String writeCommunity = DEFAULT_WRITE_COMMUNITY; /** Controls the request processing thread pool */ private int numberOfThreads = 1; /** Agent listening port */ private int port = 1161; /** Agent SNMP protocol version */ private int snmpVersion = SNMPV1; /** The interface to bind, useful for multi-homed hosts */ private InetAddress bindAddress; /** Name of the utilised timer MBean */ private ObjectName timerName = null; /** Heartbeat emission period (in seconds) and switch */ private int heartBeatPeriod = 60; /** Dynamic subscriptions flag */ private boolean dynamicSubscriptions = true; /** Reference to heartbeat emission controller */ private Heartbeat heartbeat = null; /** The trap emitting subsystem*/ private TrapEmitter trapEmitter = null; /** the snmp agent session for handling get/set requests */ private SnmpAgentSession agentSession = null; /** the request handler instance handling get/set requests */ private RequestHandler requestHandler; // Constructors -------------------------------------------------- /** * Default CTOR */ public SnmpAgentService() { // empty } // Attributes ---------------------------------------------------- /** * Gets the heartbeat switch * * @jmx:managed-attribute */ public int getHeartBeatPeriod() { return this.heartBeatPeriod; } /** * Sets the heartbeat period (in seconds) switch * * @jmx:managed-attribute */ public void setHeartBeatPeriod(int heartBeatPeriod) { this.heartBeatPeriod = heartBeatPeriod; } /** * Returns the difference, measured in milliseconds, between the * instantiation time and midnight, January 1, 1970 UTC. * * @jmx:managed-attribute */ public long getInstantiationTime() { return this.clock.instantiationTime(); } /** * Returns the up-time * * @jmx:managed-attribute */ public long getUptime() { return this.clock.uptime(); } /** * Returns the current trap counter reading * * @jmx:managed-attribute */ public long getTrapCount() { return this.trapCounter.peek(); } /** * Sets the name of the file containing SNMP manager specifications * * @jmx:managed-attribute */ public void setManagersResName(String managersResName) { this.managersResName = managersResName; } /** * Gets the name of the file containing SNMP manager specifications * * @jmx:managed-attribute */ public String getManagersResName() { return this.managersResName; } /** * Sets the name of the file containing the notification/trap mappings * * @jmx:managed-attribute */ public void setNotificationMapResName(String notificationMapResName) { this.notificationMapResName = notificationMapResName; } /** * Gets the name of the file containing the notification/trap mappings * * @jmx:managed-attribute */ public String getNotificationMapResName() { return this.notificationMapResName; } /** * Sets the utilised trap factory name * * @jmx:managed-attribute */ public void setTrapFactoryClassName(String name) { this.trapFactoryClassName = name; } /** * Gets the utilised trap factory name * * @jmx:managed-attribute */ public String getTrapFactoryClassName() { return this.trapFactoryClassName; } /** * Sets the utilised timer MBean name * * @jmx:managed-attribute */ public void setTimerName(ObjectName timerName) { this.timerName = timerName; } /** * Gets the utilised timer MBean name * * @jmx:managed-attribute */ public ObjectName getTimerName() { return this.timerName; } /** * Sets the agent bind address * * @jmx:managed-attribute */ public void setBindAddress(String bindAddress) throws UnknownHostException { this.bindAddress = toInetAddress(bindAddress); } /** * Gets the agent bind address * * @jmx:managed-attribute */ public String getBindAddress() { String address = null; if (this.bindAddress != null) address = this.bindAddress.getHostAddress(); return address; } /** * Sets the number of threads in the agent request processing thread pool * * @jmx:managed-attribute */ public void setNumberOfThreads(int numberOfThreads) { if (numberOfThreads > 0 && numberOfThreads <= 12) { this.numberOfThreads = numberOfThreads; } } /** * Gets the number of threads in the agent requests processing thread pool * * @jmx:managed-attribute */ public int getNumberOfThreads() { return numberOfThreads; } /** * Sets the agent listening port number * * @jmx:managed-attribute */ public void setPort(int port) { if (port >= 0) { this.port = port; } } /** * Gets the agent listening port number * * @jmx:managed-attribute */ public int getPort() { return port; } /** * Sets the snmp protocol version * * @jmx:managed-attribute */ public void setSnmpVersion(int snmpVersion) { switch (snmpVersion) { case SNMPV2: this.snmpVersion = SNMPV2; break; default: this.snmpVersion = SNMPV1; break; } } /** * Gets the snmp protocol version * * @jmx:managed-attribute */ public int getSnmpVersion() { return snmpVersion; } /** * Sets the read community (no getter) * * @jmx:managed-attribute */ public void setReadCommunity(String readCommunity) { if (readCommunity != null && readCommunity.length() > 0) { this.readCommunity = readCommunity; } } /** * Sets the write community (no getter) * @jmx:managed-attribute */ public void setWriteCommunity(String writeCommunity) { if (writeCommunity != null && writeCommunity.length() > 0) { this.writeCommunity = writeCommunity; } } /** * Sets the RequestHandler implementation class * * @jmx:managed-attribute */ public void setRequestHandlerClassName(String requestHandlerClassName) { this.requestHandlerClassName = requestHandlerClassName; } /** * Gets the RequestHandler implementation class * * @jmx:managed-attribute */ public String getRequestHandlerClassName() { return requestHandlerClassName; } /** * Sets the resource file name containing get/set mappings * * @jmx:managed-attribute */ public void setRequestHandlerResName(String requestHandlerResName) { this.requestHandlerResName = requestHandlerResName; } /** * Gets the resource file name containing get/set mappings * * @jmx:managed-attribute */ public String getRequestHandlerResName() { return requestHandlerResName; } /** * Enables/disables dynamic subscriptions * * @jmx:managed-attribute */ public void setDynamicSubscriptions(boolean dynamicSubscriptions) { this.dynamicSubscriptions = dynamicSubscriptions; } /** * Gets the dynamic subscriptions status * * @jmx:managed-attribute */ public boolean getDynamicSubscriptions() { return this.dynamicSubscriptions; } // Operations ---------------------------------------------------- /** * Reconfigures the RequestHandler, reponsible for handling get requests etc. * * @jmx:managed-operation */ public void reconfigureRequestHandler() throws Exception { if (requestHandler instanceof Reconfigurable) ((Reconfigurable)requestHandler).reconfigure(getRequestHandlerResName()); else throw new UnsupportedOperationException("Request handler is not Reconfigurable"); } // Lifecycle operations ------------------------------------------ /** * Perform service start-up */ protected void startService() throws Exception { // initialize clock and trapCounter this.clock = new Clock(); this.trapCounter = new Counter(0); // Notification subscription are handled by // ListenerServiceMBeanSupport baseclass log.debug("Instantiating trap emitter ..."); this.trapEmitter = new TrapEmitter(this.getTrapFactoryClassName(), this.trapCounter, this.clock, this.getManagersResName(), this.getNotificationMapResName()); // Start trap emitter log.debug("Starting trap emitter ..."); this.trapEmitter.start(); // Get the heartbeat going this.heartbeat = new Heartbeat(this.getServer(), this.getTimerName(), this.getHeartBeatPeriod()); log.debug("Starting heartbeat controller ..."); heartbeat.start(); // subscribe for notifications, with the option for dynamic subscriptions super.subscribe(this.dynamicSubscriptions); // initialise the snmp agent log.debug("Starting snmp agent ..."); startAgent(); log.info("SNMP agent going active"); // Send the cold start! this.sendNotification(new Notification(EventTypes.COLDSTART, this, getNextNotificationSequenceNumber())); } /** * Perform service shutdown */ protected void stopService() throws Exception { // unsubscribe for notifications super.unsubscribe(); log.debug("Stopping heartbeat controller ..."); this.heartbeat.stop(); this.heartbeat = null; // gc log.debug("Stopping trap emitter ..."); this.trapEmitter.stop(); this.trapEmitter = null; log.debug("Stopping snmp agent ..."); this.agentSession.close(); this.agentSession = null; log.info("SNMP agent stopped"); } // Notification handling ----------------------------------------- /** * All notifications are intercepted here and are routed for emission. */ public void handleNotification2(Notification n, Object handback) { if (log.isTraceEnabled()) { log.trace("Received notification: <" + n + "> Payload " + "TS: <" + n.getTimeStamp() + "> " + "SN: <" + n.getSequenceNumber() + "> " + "T: <" + n.getType() + ">"); } try { this.trapEmitter.send(n); } catch (Exception e) { log.error("Sending trap", e); } } // Private ------------------------------------------------------- /** * Start the embedded agent */ private void startAgent() throws Exception { // cater for possible global -b option, if no override has been specified InetAddress address = this.bindAddress != null ? this.bindAddress : toInetAddress(System.getProperty(ServerConfig.SERVER_BIND_ADDRESS)); // the listening address SnmpPeer peer = new SnmpPeer(address, this.port); // set community strings and protocol version peer.getParameters().setReadCommunity(this.readCommunity); peer.getParameters().setWriteCommunity(this.writeCommunity); peer.getParameters().setVersion(this.snmpVersion == SNMPV2 ? SnmpSMI.SNMPV2 : SnmpSMI.SNMPV1); // Instantiate and initialize the RequestHandler implementation requestHandler = (RequestHandler)Class.forName( this.requestHandlerClassName, true, this.getClass().getClassLoader()).newInstance(); requestHandler.initialize(this.requestHandlerResName, this.getServer(), this.log, this.clock); // Instantiate the AgentSession with an optional thread pool this.agentSession = this.numberOfThreads > 1 ? new SnmpAgentSession(requestHandler, peer, this.numberOfThreads) : new SnmpAgentSession(requestHandler, peer); } /** * Safely convert a host string to InetAddress or null */ private InetAddress toInetAddress(String host) throws UnknownHostException { if (host == null || host.length() == 0) return null; else return InetAddress.getByName(host); } }