001: /*
002: * Copyright (c) 2003, Intracom S.A. - www.intracom.com
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * This package and its source code is available at www.jboss.org
019: **/
020: package org.jboss.jmx.adaptor.snmp.agent;
021:
022: import java.io.InputStream;
023: import java.net.InetAddress;
024: import java.net.UnknownHostException;
025: import java.util.ArrayList;
026: import java.util.Collections;
027: import java.util.HashSet;
028: import java.util.Iterator;
029: import java.util.Set;
030:
031: import javax.management.Notification;
032:
033: import org.jboss.jmx.adaptor.snmp.config.manager.Manager;
034: import org.jboss.logging.Logger;
035: import org.jboss.system.server.ServerConfig;
036: import org.jboss.xb.binding.MappingObjectModelFactory;
037: import org.jboss.xb.binding.Unmarshaller;
038: import org.jboss.xb.binding.UnmarshallerFactory;
039: import org.opennms.protocols.snmp.SnmpIPAddress;
040: import org.opennms.protocols.snmp.SnmpPduPacket;
041: import org.opennms.protocols.snmp.SnmpPduTrap;
042:
043: /**
044: * <tt>TrapEmitter</tt> is a class that manages SNMP trap emission.
045: *
046: * Currently, it allows to send V1 or V2 traps to one or more subscribed SNMP
047: * managers defined by their IP address, listening port number and expected
048: * SNMP version.
049: *
050: * @version $Revision: 32504 $
051: *
052: * @author <a href="mailto:spol@intracom.gr">Spyros Pollatos</a>
053: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
054: **/
055: public class TrapEmitter {
056: /** The logger object */
057: private static final Logger log = Logger
058: .getLogger(TrapEmitter.class);
059:
060: /** Reference to the utilised trap factory*/
061: private TrapFactory trapFactory = null;
062:
063: /** The actual trap factory to instantiate */
064: private String trapFactoryClassName = null;
065:
066: /** The managers resource name */
067: private String managersResName = null;
068:
069: /** The notification map resource name */
070: private String notificationMapResName = null;
071:
072: /** Provides trap count */
073: private Counter trapCount = null;
074:
075: /** Uptime clock */
076: private Clock uptime = null;
077:
078: /** Holds the manager subscriptions. Accessed through synch'd wrapper */
079: private Set managers = Collections.synchronizedSet(new HashSet());
080:
081: /**
082: * Builds a TrapEmitter object for sending SNMP V1 or V2 traps. <P>
083: **/
084: public TrapEmitter(String trapFactoryClassName, Counter trapCount,
085: Clock uptime, String managersResName,
086: String notificationMapResName) {
087: this .trapFactoryClassName = trapFactoryClassName;
088: this .trapCount = trapCount;
089: this .uptime = uptime;
090: this .managersResName = managersResName;
091: this .notificationMapResName = notificationMapResName;
092: }
093:
094: /**
095: * Complete emitter initialisation
096: **/
097: public void start() throws Exception {
098: // Load persisted manager subscriptions
099: load();
100:
101: // Instantiate the trap factory
102: this .trapFactory = (TrapFactory) Class.forName(
103: this .trapFactoryClassName, true,
104: this .getClass().getClassLoader()).newInstance();
105:
106: // Initialise
107: this .trapFactory.set(this .notificationMapResName, this .uptime,
108: this .trapCount);
109:
110: // Start the trap factory
111: this .trapFactory.start();
112: }
113:
114: /**
115: * Perform shutdown
116: **/
117: public void stop() throws Exception {
118: synchronized (this .managers) {
119:
120: // Recycle open sessions to managers
121: Iterator i = this .managers.iterator();
122:
123: while (i.hasNext()) {
124: ManagerRecord s = (ManagerRecord) i.next();
125: s.closeSession();
126: }
127:
128: // Drop all held manager records
129: this .managers.clear();
130: }
131: }
132:
133: /**
134: * Intercepts the notification and after translating it to a trap sends it
135: * along.
136: *
137: * @param n notification to be sent
138: * @throws Exception if an error occurs during the preparation or
139: * sending of the trap
140: **/
141: public void send(Notification n) throws Exception {
142: // Beeing paranoid
143: synchronized (this .trapFactory) {
144: if (this .trapFactory == null) {
145: log
146: .error("Received notifications before trap factory set. Discarding.");
147: return;
148: }
149: }
150:
151: // Cache the translated notification
152: SnmpPduTrap v1TrapPdu = null;
153: SnmpPduPacket v2TrapPdu = null;
154:
155: // Send trap. Synchronise on the subscription collection while
156: // iterating
157: synchronized (this .managers) {
158:
159: // Iterate over sessions and emit the trap on each one
160: Iterator i = this .managers.iterator();
161: while (i.hasNext()) {
162: ManagerRecord s = (ManagerRecord) i.next();
163:
164: try {
165: switch (s.getVersion()) {
166: case SnmpAgentService.SNMPV1:
167: if (v1TrapPdu == null)
168: v1TrapPdu = this .trapFactory
169: .generateV1Trap(n);
170:
171: // fix the agent ip in the trap depending on which local address is bound
172: v1TrapPdu.setAgentAddress(new SnmpIPAddress(s
173: .getLocalAddress()));
174:
175: // Advance the trap counter
176: this .trapCount.advance();
177:
178: // Send
179: s.getSession().send(v1TrapPdu);
180: break;
181:
182: case SnmpAgentService.SNMPV2:
183: if (v2TrapPdu == null)
184: v2TrapPdu = this .trapFactory
185: .generateV2Trap(n);
186:
187: // Advance the trap counter
188: this .trapCount.advance();
189:
190: // Send
191: s.getSession().send(v2TrapPdu);
192: break;
193:
194: default:
195: log
196: .error("Skipping session: Unknown SNMP version found");
197: }
198: } catch (MappingFailedException e) {
199: log.error("Translating notification - "
200: + e.getMessage());
201: } catch (Exception e) {
202: log.error("SNMP send error for "
203: + s.getAddress().toString() + ":"
204: + s.getPort() + ": <" + e + ">");
205: }
206: }
207: }
208: }
209:
210: /**
211: * Load manager subscriptions
212: **/
213: private void load() throws Exception {
214: log.debug("Reading resource: '" + this .managersResName + "'");
215:
216: // configure ObjectModelFactory for mapping XML to POJOs
217: // we'll be simply getting an ArrayList of Manager objects
218: MappingObjectModelFactory momf = new MappingObjectModelFactory();
219: momf.mapElementToClass("manager-list", ArrayList.class);
220: momf.mapElementToClass("manager", Manager.class);
221:
222: ArrayList managerList = null;
223: InputStream is = null;
224: try {
225: // locate managers.xml
226: is = this .getClass().getResourceAsStream(
227: this .managersResName);
228:
229: // create unmarshaller
230: Unmarshaller unmarshaller = UnmarshallerFactory
231: .newInstance().newUnmarshaller();
232:
233: // let JBossXB do it's magic using the MappingObjectModelFactory
234: managerList = (ArrayList) unmarshaller.unmarshal(is, momf,
235: null);
236: } catch (Exception e) {
237: log.error("Accessing resource '" + managersResName + "'");
238: throw e;
239: } finally {
240: if (is != null) {
241: // close the XML stream
242: is.close();
243: }
244: }
245: log.debug("Found " + managerList.size()
246: + " monitoring managers");
247:
248: for (Iterator i = managerList.iterator(); i.hasNext();) {
249: // Read the monitoring manager's particulars
250: Manager m = (Manager) i.next();
251:
252: try {
253: // Create a record of the manager's interest
254: ManagerRecord mr = new ManagerRecord(InetAddress
255: .getByName(m.getAddress()), m.getPort(),
256: toInetAddressWithDefaultBinding(m
257: .getLocalAddress()), m.getLocalPort(),
258: m.getVersion());
259:
260: // Add the record to the list of monitoring managers. If
261: // successfull open the session to the manager as well.
262: if (this .managers.add(mr) == false) {
263: log.warn("Ignoring duplicate manager: " + m);
264: } else {
265: // Open the session to the manager
266: mr.openSession();
267: }
268: } catch (Exception e) {
269: log.warn("Error enabling monitoring manager: " + m, e);
270: }
271: }
272: }
273:
274: /**
275: * cater for possible global -b option, if no override has been specified
276: */
277: private InetAddress toInetAddressWithDefaultBinding(String host)
278: throws UnknownHostException {
279: if (host == null || host.length() == 0) {
280:
281: String defaultBindAddress = System
282: .getProperty(ServerConfig.SERVER_BIND_ADDRESS);
283: if (defaultBindAddress != null
284: && !defaultBindAddress.equals("0.0.0.0"))
285: return InetAddress.getByName(defaultBindAddress);
286: else
287: return InetAddress.getLocalHost();
288: } else
289: return InetAddress.getByName(host);
290: }
291:
292: } // class TrapEmitter
|