View Javadoc

1   package net.sf.snmpadaptor4j;
2   
3   import java.net.URL;
4   import java.util.ArrayList;
5   import java.util.Collections;
6   import java.util.HashMap;
7   import java.util.List;
8   import java.util.Map;
9   import javax.management.MBeanAttributeInfo;
10  import javax.management.MBeanConstructorInfo;
11  import javax.management.MBeanInfo;
12  import javax.management.MBeanNotificationInfo;
13  import javax.management.MBeanOperationInfo;
14  import javax.management.MBeanParameterInfo;
15  import javax.management.MBeanServer;
16  import javax.management.ObjectName;
17  import javax.management.StandardMBean;
18  import net.sf.snmpadaptor4j.api.SnmpApiFactory;
19  import net.sf.snmpadaptor4j.api.SnmpDaemon;
20  import net.sf.snmpadaptor4j.api.opennms.OpennmsSnmpApiFactory;
21  import net.sf.snmpadaptor4j.config.XmlConfigParser;
22  import net.sf.snmpadaptor4j.core.JmxListener;
23  import net.sf.snmpadaptor4j.core.JmxNotificationManager;
24  import net.sf.snmpadaptor4j.core.JmxSnmpMib;
25  import net.sf.snmpadaptor4j.core.JvmSnmpMib;
26  import net.sf.snmpadaptor4j.core.SystemSnmpMib;
27  import net.sf.snmpadaptor4j.core.trap.SnmpManagers;
28  import net.sf.snmpadaptor4j.mbean.SystemInfo;
29  import org.apache.log4j.Logger;
30  
31  /**
32   * <p>
33   * snmpAdaptor4j is an adaptor for <a href="http://en.wikipedia.org/wiki/Java_Management_Extensions" target="_blank">Java Management eXtensions (JMX)</a> providing a
34   * simple access to MBeans via the <a href="http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol" target="_blank">SNMP</a> protocol. Thus, this adapter
35   * you allow to connect most monitoring tools (like <a href="http://www.nagios.org/" target="_blank">Nagios</a> and <a href="http://www.cacti.net"
36   * target="_blank">Cacti</a>) to your Java applications.
37   * </p>
38   * <p>
39   * For each MBean, an XML mapping file allows to establish the relationships between attributes and the MIB of the SNMP adapter. No additional code is necessary to
40   * integrate the MBeans in the SNMP protocol.
41   * </p>
42   * <p>
43   * This adapter can work in a multi-applications environment (such as application servers).
44   * </p>
45   * <h4>Building of the mapping files</h4>
46   * <p>
47   * For each MBean of your project, create the mapping file in the <u>same package as the MBean</u>. For example:
48   * </p>
49   * <code>
50   *        &lt;?xml version="1.0" encoding="utf-8"?&gt;<br>
51   *        &lt;snmpAdaptor4j-mapping<br>
52   *        &nbsp;&nbsp;&nbsp;&nbsp;xmlns="http://www.sf.net/snmpAdaptor4j/mapping/1.1"<br>
53   *        &nbsp;&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br>
54   *        &nbsp;&nbsp;&nbsp;&nbsp;xsi:schemaLocation="http://www.sf.net/snmpAdaptor4j/mapping/1.1<br>
55   *        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://snmpAdaptor4j.sourceforge.net/xsd/snmpAdaptor4j-mapping-1.1.xsd"&gt;<br><br>
56   *        &nbsp;&nbsp;&lt;attributes&gt;<br>
57   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;attribute name="attributA" type="integer32" node="1" writable="true"/&gt;<br>
58   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;attribute name="attributB" type="counter64" node="2" writable="false"/&gt;<br>
59   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;attribute name="attributC" type="gauge32" node="3" writable="false"/&gt;<br>
60   *        &nbsp;&nbsp;&lt;/attributes&gt;<br><br>
61   *        &lt;/snmpAdaptor4j-mapping&gt;
62   * 	  </code>
63   * <p>
64   * Here, we map only MBean attributes by indicating the SNMP data type and the node constituting the OID (Object IDentifier). The mapping of MBean instances, is
65   * generally put in the configuration file (see next chapter).
66   * </p>
67   * <h4>Building of the configuration file</h4>
68   * <p>
69   * Create the configuration file (one by application) like this:
70   * </p>
71   * <code>
72   *        &lt;?xml version="1.0" encoding="utf-8"?&gt;<br>
73   *        &lt;snmpAdaptor4j-config<br>
74   *        &nbsp;&nbsp;&nbsp;&nbsp;xmlns="http://www.sf.net/snmpAdaptor4j/config/1.1"<br>
75   *        &nbsp;&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br>
76   *        &nbsp;&nbsp;&nbsp;&nbsp;xsi:schemaLocation="http://www.sf.net/snmpAdaptor4j/config/1.1<br>
77   *        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://snmpAdaptor4j.sourceforge.net/xsd/snmpAdaptor4j-config-1.1.xsd"&gt;<br><br>
78   *        &nbsp;&nbsp;&lt;daemon address="127.0.0.1" port="161" version="2"&gt;<br>
79   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;readCommunity&gt;public&lt;/readCommunity&gt;<br>
80   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;writeCommunity&gt;private&lt;/writeCommunity&gt;<br>
81   *        &nbsp;&nbsp;&lt;/daemon&gt;<br><br>
82   *        &nbsp;&nbsp;&lt;roots default="1.3.6.1.4.1.99.12.8.1"/&gt;<br><br>
83   *        &nbsp;&nbsp;&lt;mbeans&gt;<br>
84   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;mbean name="fr.mydomain.myAppli:type=MyClass,name=objA" oid="1.1"/&gt;<br>
85   *        &nbsp;&nbsp;&nbsp;&nbsp;&lt;mbean name="fr.mydomain.myAppli:type=MyClass,name=objB" oid="1.2"/&gt;<br>
86   *        &nbsp;&nbsp;&lt;/mbeans&gt;<br><br>
87   *        &lt;/snmpAdaptor4j-config&gt;
88   * 	  </code>
89   * <p>
90   * Here, we define the OID for each instance of MBeans. The OID of an attribute, is built as follows:
91   * </p>
92   * <code>
93   * 	  ${root}.${mbean oid}.${attribute node}.0
94   * 	  </code>
95   * <p>
96   * For example, the <i>attributB</i> OID of first MBean will be <b>1.3.6.1.4.1.99.12.8.1.1.1.2.0</b>.
97   * </p>
98   * <h4>Registration and start of adaptor</h4>
99   * <p>
100  * Insert the following code to install the adapter inside JMX:
101  * </p>
102  * <code>
103  *      URL url = getClass().getResource("/snmp.xml");<br>
104  *      SnmpAdaptor adaptor = new SnmpAdaptor(url, true);<br>
105  *      ObjectName name = new ObjectName("net.sf.snmpadaptor4j:adaptor=SnmpAdaptor");<br>
106  *      ManagementFactory.getPlatformMBeanServer().registerMBean(adaptor, name);
107  * 	  </code>
108  * <p>
109  * <i>snmp.xml</i> is the configuration file previously built.
110  * </p>
111  * <p>
112  * Update the information about your system:
113  * </p>
114  * <code>
115  *      adaptor.getSystemInfo().setSysName("MyApp");<br>
116  *      adaptor.getSystemInfo().setSysDescr("This is a java application");<br>
117  *      adaptor.getSystemInfo().setSysLocation("Web server at Montpellier (France)");<br>
118  *      adaptor.getSystemInfo().setSysContact("root@mydomain.fr");
119  * </code>
120  * <p>
121  * Start the adaptor:
122  * </p>
123  * <code>
124  *      snmpAdaptor.start();
125  * </code> <h4>Test</h4>
126  * <p>
127  * Install the <a href="http://www.net-snmp.org">Net-SNMP</a> commands and type:
128  * </p>
129  * <code>
130  * 	  snmpwalk -v2c -Os -c public 127.0.0.1 .1
131  * 	  </code>
132  * <p>
133  * You should see the attribute values of your MBean.
134  * </p>
135  * @author <a href="http://fr.linkedin.com/in/jpminetti/">Jean-Philippe MINETTI</a>
136  */
137 public class SnmpAdaptor
138 		extends StandardMBean
139 		implements SnmpConfiguration, SnmpAppContext, SnmpAdaptorMBean {
140 
141 	/**
142 	 * Logger.
143 	 */
144 	private final Logger logger = Logger.getLogger(SnmpAdaptor.class);
145 
146 	/**
147 	 * SNMP daemon.
148 	 */
149 	private final SnmpDaemon daemon;
150 
151 	/**
152 	 * Informations on the system.
153 	 */
154 	private final SystemInfo systemInfo;
155 
156 	/**
157 	 * Listening IP address of SNMP daemon (127.0.0.1 by default).
158 	 */
159 	private String listenerAddress = null;
160 
161 	/**
162 	 * UDP port of SNMP daemon (161 by default).
163 	 */
164 	private Integer listenerPort = null;
165 
166 	/**
167 	 * Protocol version of SNMP daemon (SNMP v2 by default).
168 	 */
169 	private Integer listenerSnmpVersion = null;
170 
171 	/**
172 	 * Read community of SNMP daemon ("public" by default).
173 	 */
174 	private String listenerReadCommunity = null;
175 
176 	/**
177 	 * Write community of SNMP daemon ("private" by default).
178 	 */
179 	private String listenerWriteCommunity = null;
180 
181 	/**
182 	 * List of managers where to send all notifications (SNMP traps).
183 	 */
184 	private final List<SnmpManagerConfiguration> managerList = new ArrayList<SnmpManagerConfiguration>();
185 
186 	/**
187 	 * Default root OID containing the attributes of the application.
188 	 */
189 	private final String defaultRootOid;
190 
191 	/**
192 	 * Map of root OIDs where the attributes of the application will stay.
193 	 */
194 	private final Map<String, String> rootOidMap;
195 
196 	/**
197 	 * Map of MBean OIDs.
198 	 */
199 	private final Map<ObjectName, String> mBeanOidMap;
200 
201 	/**
202 	 * Application context map.
203 	 */
204 	protected final Map<ClassLoader, SnmpAppContext> appContextMap = new HashMap<ClassLoader, SnmpAppContext>();
205 
206 	/**
207 	 * SNMP managers on the network to which SNMP traps should be sent.
208 	 */
209 	private final SnmpManagers snmpManagers;
210 
211 	/**
212 	 * <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB) for system attributes.
213 	 */
214 	private final SystemSnmpMib systemMib;
215 
216 	/**
217 	 * <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB) for attributes of JVM.
218 	 */
219 	private final JvmSnmpMib jvmMib;
220 
221 	/**
222 	 * Manager of JMX notifications.
223 	 */
224 	private final JmxNotificationManager jmxNotificationManager;
225 
226 	/**
227 	 * Object designed to respond to each registration or deregistration of MBeans.
228 	 */
229 	private final JmxListener jmxListener;
230 
231 	/**
232 	 * Constructor with a minimum of parameters.
233 	 * <p>
234 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
235 	 * </p>
236 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
237 	 *            all MBeans of the JVM.
238 	 * @throws Exception Exception if an error has occurred.
239 	 */
240 	public SnmpAdaptor (final boolean classLoaderScope) throws Exception {
241 		this(null, null, null, classLoaderScope);
242 	}
243 
244 	/**
245 	 * Constructor with an application context.
246 	 * <p>
247 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
248 	 * </p>
249 	 * @param appContext Application context.
250 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
251 	 *            all MBeans of the JVM.
252 	 * @throws Exception Exception if an error has occurred.
253 	 */
254 	public SnmpAdaptor (final SnmpAppContext appContext, final boolean classLoaderScope) throws Exception {
255 		this(null, appContext, null, classLoaderScope);
256 	}
257 
258 	/**
259 	 * Constructor with an {@link URL} to SNMP configuration file (XML).
260 	 * <p>
261 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
262 	 * </p>
263 	 * @param url {@link URL} of SNMP configuration file (XML).
264 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
265 	 *            all MBeans of the JVM.
266 	 * @throws Exception Exception if an error occurred.
267 	 */
268 	public SnmpAdaptor (final URL url, final boolean classLoaderScope) throws Exception {
269 		this(url, null, classLoaderScope);
270 	}
271 
272 	/**
273 	 * Constructor with an {@link URL} to SNMP configuration file (XML) and a {@link SystemInfo}.
274 	 * <p>
275 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
276 	 * </p>
277 	 * @param url {@link URL} of SNMP configuration file (XML).
278 	 * @param systemInfo Informations on the system.
279 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
280 	 *            all MBeans of the JVM.
281 	 * @throws Exception Exception if an error occurred.
282 	 */
283 	public SnmpAdaptor (final URL url, final SystemInfo systemInfo, final boolean classLoaderScope) throws Exception {
284 		this(XmlConfigParser.newInstance(url), systemInfo, classLoaderScope);
285 	}
286 
287 	/**
288 	 * Hidden constructor.
289 	 * <p>
290 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
291 	 * </p>
292 	 * @param xmlConfigParser Parser of SNMP configuration file (XML).
293 	 * @param systemInfo Informations on the system.
294 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
295 	 *            all MBeans of the JVM.
296 	 * @throws Exception Exception if an error has occurred.
297 	 */
298 	private SnmpAdaptor (final XmlConfigParser xmlConfigParser, final SystemInfo systemInfo, final boolean classLoaderScope) throws Exception {
299 		this(xmlConfigParser, xmlConfigParser, systemInfo, classLoaderScope);
300 	}
301 
302 	/**
303 	 * Constructor with all parameters.
304 	 * <p>
305 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
306 	 * </p>
307 	 * @param configuration SNMP configuration settings.
308 	 * @param appContext Application context.
309 	 * @param systemInfo Informations on the system.
310 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
311 	 *            all MBeans of the JVM.
312 	 * @throws Exception Exception if an error has occurred.
313 	 */
314 	public SnmpAdaptor (final SnmpConfiguration configuration, final SnmpAppContext appContext, final SystemInfo systemInfo, final boolean classLoaderScope)
315 			throws Exception {
316 		super(SnmpAdaptorMBean.class);
317 		initializeMBeanDescriptions();
318 		this.defaultRootOid = ((appContext != null) && (appContext.getDefaultRootOid() != null) ? appContext.getDefaultRootOid() : "1.3.6.1.4.1.99.12.8.1");
319 		this.rootOidMap = Collections.unmodifiableMap(appContext != null ? appContext.getRootOidMap() : new HashMap<String, String>());
320 		this.mBeanOidMap = Collections.unmodifiableMap(appContext != null ? appContext.getMBeanOidMap() : new HashMap<ObjectName, String>());
321 		this.systemInfo = (systemInfo != null ? systemInfo : new SystemInfo());
322 		this.systemMib = new SystemSnmpMib(this, this.appContextMap, this.systemInfo);
323 		this.jvmMib = new JvmSnmpMib(this.systemMib);
324 		final JmxSnmpMib jmxSnmpMib = new JmxSnmpMib(this.jvmMib);
325 		final SnmpApiFactory apiFactory = new OpennmsSnmpApiFactory();
326 		this.snmpManagers = new SnmpManagers(apiFactory);
327 		this.jmxNotificationManager = new JmxNotificationManager(this.snmpManagers, this.systemInfo);
328 		this.jmxListener = new JmxListener(jmxSnmpMib, this.jmxNotificationManager, this, this.appContextMap, classLoaderScope);
329 		this.daemon = apiFactory.newSnmpDaemon(this, jmxSnmpMib);
330 		setListenerAddress(configuration != null ? configuration.getListenerAddress() : null);
331 		setListenerPort(configuration != null ? configuration.getListenerPort() : null);
332 		setListenerSnmpVersion(configuration != null ? configuration.getListenerSnmpVersion() : null);
333 		setListenerReadCommunity(configuration != null ? configuration.getListenerReadCommunity() : null);
334 		setListenerWriteCommunity(configuration != null ? configuration.getListenerWriteCommunity() : null);
335 		if ((configuration != null) && (configuration.getManagerList() != null)) {
336 			this.managerList.addAll(configuration.getManagerList());
337 			this.snmpManagers.initialize(this.managerList);
338 		}
339 	}
340 
341 	/**
342 	 * Hidden constructor (used for tests only).
343 	 * <p>
344 	 * Set <code>TRUE</code> to <code>classLoaderScope</code> for web applications: this avoids to publish MBeans of other applications of application server.
345 	 * </p>
346 	 * @param defaultRootOid Default root OID containing the attributes of the application.
347 	 * @param configuration SNMP configuration settings.
348 	 * @param classLoaderScope <code>TRUE</code> for handle only MBeans created by the same {@link ClassLoader} that the SNMP adapter. <code>FALSE</code> for handle
349 	 *            all MBeans of the JVM.
350 	 * @param systemMib <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB) for system attributes.
351 	 * @param jvmMib <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB) for attributes of JVM.
352 	 * @param jmxListener Object designed to respond to each registration or deregistration of MBeans.
353 	 * @param jmxNotificationManager Manager of JMX notifications.
354 	 * @param daemon SNMP daemon.
355 	 * @throws Exception Exception if an error has occurred.
356 	 */
357 	protected SnmpAdaptor (final String defaultRootOid, final SnmpConfiguration configuration, final boolean classLoaderScope, final SystemSnmpMib systemMib,
358 			final JvmSnmpMib jvmMib, final JmxListener jmxListener, final JmxNotificationManager jmxNotificationManager, final SnmpDaemon daemon) throws Exception {
359 		super(SnmpAdaptorMBean.class);
360 		initializeMBeanDescriptions();
361 		this.defaultRootOid = defaultRootOid;
362 		this.rootOidMap = Collections.unmodifiableMap(new HashMap<String, String>());
363 		this.mBeanOidMap = Collections.unmodifiableMap(new HashMap<ObjectName, String>());
364 		this.systemInfo = new SystemInfo();
365 		this.systemMib = systemMib;
366 		this.jvmMib = jvmMib;
367 		this.snmpManagers = null;
368 		this.jmxNotificationManager = jmxNotificationManager;
369 		this.jmxListener = jmxListener;
370 		this.daemon = daemon;
371 		setListenerAddress(configuration != null ? configuration.getListenerAddress() : null);
372 		setListenerPort(configuration != null ? configuration.getListenerPort() : null);
373 		setListenerSnmpVersion(configuration != null ? configuration.getListenerSnmpVersion() : null);
374 		setListenerReadCommunity(configuration != null ? configuration.getListenerReadCommunity() : null);
375 		setListenerWriteCommunity(configuration != null ? configuration.getListenerWriteCommunity() : null);
376 		if ((configuration != null) && (configuration.getManagerList() != null)) {
377 			this.managerList.addAll(configuration.getManagerList());
378 		}
379 	}
380 
381 	/**
382 	 * Initializes all descriptions of MBean and its members.
383 	 */
384 	private void initializeMBeanDescriptions () {
385 
386 		// Descriptions
387 		final String classDescription = "JMX adaptor for SNMP protocol";
388 		final String listenerAddressAttributeDescription = "Listening IP address of SNMP daemon";
389 		final String listenerPortAttributeDescription = "Listening UDP port of SNMP daemon";
390 		final String listenerSnmpVersionAttributeDescription = "Protocol version of SNMP daemon (1 or 2)";
391 		final String listenerReadCommunityAttributeDescription = "Read community of SNMP daemon";
392 		final String listenerWriteCommunityAttributeDescription = "Write community of SNMP daemon";
393 		final String managerListAttributeDescription = "List of managers where to send all notifications (SNMP traps)";
394 		final String startedAttributeDescription = "TRUE if the SNMP daemon is started";
395 		final String addAppContextDescription = "Adds a new application context";
396 		final String removeAppContextDescription = "Removes an application context";
397 		final String startDescription = "Starts the SNMP daemon";
398 		final String stopDescription = "Stops the SNMP daemon";
399 		final String classLoaderParameterDescription = "Class loader of application";
400 		final String appContextParameterDescription = "Application context (any class that implements the interface " + SnmpAppContext.class.getName() + ")";
401 		final String urlParameterDescription = "URL of SNMP configuration file (XML)";
402 		final String configurationParameterDescription = "SNMP configuration settings (any class that implements the interface " + SnmpConfiguration.class.getName()
403 				+ ")";
404 		final String systemInfoParameterDescription = "Informations on the Java application";
405 		final String classLoaderScopeParameterDescription = "TRUE for handle only MBeans created by the same ClassLoader that the SNMP adapter - FALSE for handle all MBeans of the JVM (set TRUE to classLoaderScope for web applications: this avoids to publish MBeans of other applications of application server)";
406 
407 		// Parameter info
408 		final MBeanParameterInfo classLoaderParameter = new MBeanParameterInfo("classLoader", ClassLoader.class.getName(), classLoaderParameterDescription);
409 
410 		final MBeanParameterInfo appContextParameter = new MBeanParameterInfo("appContext", SnmpAppContext.class.getName(), appContextParameterDescription);
411 		final MBeanParameterInfo urlParameter = new MBeanParameterInfo("url", URL.class.getName(), urlParameterDescription);
412 		final MBeanParameterInfo configurationParameter = new MBeanParameterInfo("configuration", SnmpConfiguration.class.getName(),
413 				configurationParameterDescription);
414 		final MBeanParameterInfo systemInfoParameter = new MBeanParameterInfo("systemInfo", SystemInfo.class.getName(), systemInfoParameterDescription);
415 		final MBeanParameterInfo classLoaderScopeParameter = new MBeanParameterInfo("classLoaderScope", boolean.class.getName(),
416 				classLoaderScopeParameterDescription);
417 
418 		// Operation info
419 		final MBeanOperationInfo addAppContextOperation = new MBeanOperationInfo("addAppContext", addAppContextDescription, new MBeanParameterInfo[] {
420 				classLoaderParameter, appContextParameter }, void.class.getName(), MBeanOperationInfo.ACTION);
421 		final MBeanOperationInfo removeAppContextOperation = new MBeanOperationInfo("removeAppContext", removeAppContextDescription,
422 				new MBeanParameterInfo[] { classLoaderParameter }, void.class.getName(), MBeanOperationInfo.ACTION);
423 		final MBeanOperationInfo startOperation = new MBeanOperationInfo("start", startDescription, new MBeanParameterInfo[] {}, void.class.getName(),
424 				MBeanOperationInfo.ACTION);
425 		final MBeanOperationInfo stopOperation = new MBeanOperationInfo("stop", stopDescription, new MBeanParameterInfo[] {}, void.class.getName(),
426 				MBeanOperationInfo.ACTION);
427 		final MBeanOperationInfo[] operations = new MBeanOperationInfo[] { addAppContextOperation, removeAppContextOperation, startOperation, stopOperation };
428 
429 		// Constructor info
430 		final MBeanConstructorInfo constructor1 = new MBeanConstructorInfo(getClass().getName(), "Constructor with only classLoaderScope parameter",
431 				new MBeanParameterInfo[] { classLoaderScopeParameter });
432 		final MBeanConstructorInfo constructor2 = new MBeanConstructorInfo(getClass().getName(), "Constructor with only appContext and classLoaderScope parameters",
433 				new MBeanParameterInfo[] { appContextParameter, classLoaderScopeParameter });
434 		final MBeanConstructorInfo constructor3 = new MBeanConstructorInfo(getClass().getName(), "Constructor with only url and classLoaderScope parameters",
435 				new MBeanParameterInfo[] { urlParameter, classLoaderScopeParameter });
436 		final MBeanConstructorInfo constructor4 = new MBeanConstructorInfo(getClass().getName(),
437 				"Constructor with only url, systemInfo and classLoaderScope parameters", new MBeanParameterInfo[] { urlParameter, systemInfoParameter,
438 						classLoaderScopeParameter });
439 		final MBeanConstructorInfo constructor5 = new MBeanConstructorInfo(getClass().getName(),
440 				"Constructor with configuration, appContext, systemInfo and classLoaderScope parameters", new MBeanParameterInfo[] { configurationParameter,
441 						appContextParameter, systemInfoParameter, classLoaderScopeParameter });
442 		final MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[] { constructor1, constructor2, constructor3, constructor4, constructor5 };
443 
444 		// Attribute info
445 		final MBeanAttributeInfo listenerAddressAttribute = new MBeanAttributeInfo("ListenerAddress", String.class.getName(), listenerAddressAttributeDescription,
446 				true, true, false);
447 		final MBeanAttributeInfo listenerPortAttribute = new MBeanAttributeInfo("ListenerPort", Integer.class.getName(), listenerPortAttributeDescription, true,
448 				true, false);
449 		final MBeanAttributeInfo listenerSnmpVersionAttribute = new MBeanAttributeInfo("ListenerSnmpVersion", Integer.class.getName(),
450 				listenerSnmpVersionAttributeDescription, true, true, false);
451 		final MBeanAttributeInfo listenerReadCommunityAttribute = new MBeanAttributeInfo("ListenerReadCommunity", String.class.getName(),
452 				listenerReadCommunityAttributeDescription, true, true, false);
453 		final MBeanAttributeInfo listenerWriteCommunityAttribute = new MBeanAttributeInfo("ListenerWriteCommunity", String.class.getName(),
454 				listenerWriteCommunityAttributeDescription, true, true, false);
455 		final MBeanAttributeInfo managerListAttribute = new MBeanAttributeInfo("ManagerList", List.class.getName(), managerListAttributeDescription, true, true,
456 				false);
457 		final MBeanAttributeInfo startedAttribute = new MBeanAttributeInfo("Started", boolean.class.getName(), startedAttributeDescription, true, false, true);
458 		final MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[] { listenerAddressAttribute, listenerPortAttribute, listenerSnmpVersionAttribute,
459 				listenerReadCommunityAttribute, listenerWriteCommunityAttribute, managerListAttribute, startedAttribute };
460 
461 		// MBeanInfo
462 		final MBeanInfo mBeanInfo = new MBeanInfo(getClass().getName(), classDescription, attributes, constructors, operations, new MBeanNotificationInfo[] {},
463 				getMBeanInfo().getDescriptor());
464 		cacheMBeanInfo(mBeanInfo);
465 
466 	}
467 
468 	/*
469 	 * {@inheritDoc}
470 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#addAppContext(java.lang.ClassLoader, net.sf.snmpadaptor4j.SnmpAppContext)
471 	 */
472 	public void addAppContext (final ClassLoader classLoader, final SnmpAppContext appContext) {
473 		synchronized (this.appContextMap) {
474 			this.appContextMap.put(classLoader, appContext);
475 			this.systemMib.initSysObjectIDSet();
476 		}
477 	}
478 
479 	/*
480 	 * {@inheritDoc}
481 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#removeAppContext(java.lang.ClassLoader)
482 	 */
483 	public void removeAppContext (final ClassLoader classLoader) {
484 		synchronized (this.appContextMap) {
485 			this.appContextMap.remove(classLoader);
486 			this.systemMib.initSysObjectIDSet();
487 		}
488 	}
489 
490 	/*
491 	 * {@inheritDoc}
492 	 * @see net.sf.snmpadaptor4j.api.SnmpDaemonConfiguration#getListenerAddress()
493 	 */
494 	public final String getListenerAddress () {
495 		return this.listenerAddress;
496 	}
497 
498 	/*
499 	 * {@inheritDoc}
500 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#setListenerAddress(java.lang.String)
501 	 */
502 	public final void setListenerAddress (final String listenerAddress) {
503 		String newListenerAddress = formatAttribute(listenerAddress);
504 		if (newListenerAddress == null) {
505 			newListenerAddress = "localhost";
506 		}
507 		if (this.listenerAddress != null ? !this.listenerAddress.equals(newListenerAddress) : true) {
508 			try {
509 				this.daemon.stop();
510 				this.jmxNotificationManager.setEnabled(false);
511 				this.listenerAddress = newListenerAddress;
512 			}
513 			catch (final Throwable e) {
514 				this.logger.error(e);
515 			}
516 		}
517 	}
518 
519 	/*
520 	 * {@inheritDoc}
521 	 * @see net.sf.snmpadaptor4j.api.SnmpDaemonConfiguration#getListenerPort()
522 	 */
523 	public final Integer getListenerPort () {
524 		return this.listenerPort;
525 	}
526 
527 	/*
528 	 * {@inheritDoc}
529 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#setListenerPort(java.lang.Integer)
530 	 */
531 	public final void setListenerPort (final Integer listenerPort) {
532 		final Integer newListenerPort = (listenerPort != null ? listenerPort : new Integer(161));
533 		if (this.listenerPort != null ? !this.listenerPort.equals(newListenerPort) : true) {
534 			try {
535 				this.daemon.stop();
536 				this.jmxNotificationManager.setEnabled(false);
537 				this.listenerPort = newListenerPort;
538 			}
539 			catch (final Throwable e) {
540 				this.logger.error(e);
541 			}
542 		}
543 	}
544 
545 	/*
546 	 * {@inheritDoc}
547 	 * @see net.sf.snmpadaptor4j.api.SnmpDaemonConfiguration#getListenerSnmpVersion()
548 	 */
549 	public final Integer getListenerSnmpVersion () {
550 		return this.listenerSnmpVersion;
551 	}
552 
553 	/*
554 	 * {@inheritDoc}
555 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#setListenerSnmpVersion(java.lang.Integer)
556 	 */
557 	public final void setListenerSnmpVersion (final Integer listenerSnmpVersion) {
558 		Integer newListenerSnmpVersion;
559 		if ((listenerSnmpVersion == null) || (listenerSnmpVersion.intValue() < 1) || (listenerSnmpVersion.intValue() > 2)) {
560 			newListenerSnmpVersion = new Integer(2);
561 		}
562 		else {
563 			newListenerSnmpVersion = listenerSnmpVersion;
564 		}
565 		if (this.listenerSnmpVersion != null ? !this.listenerSnmpVersion.equals(newListenerSnmpVersion) : true) {
566 			try {
567 				this.daemon.stop();
568 				this.jmxNotificationManager.setEnabled(false);
569 				this.listenerSnmpVersion = newListenerSnmpVersion;
570 			}
571 			catch (final Throwable e) {
572 				this.logger.error(e);
573 			}
574 		}
575 	}
576 
577 	/*
578 	 * {@inheritDoc}
579 	 * @see net.sf.snmpadaptor4j.api.SnmpDaemonConfiguration#getListenerReadCommunity()
580 	 */
581 	public final String getListenerReadCommunity () {
582 		return this.listenerReadCommunity;
583 	}
584 
585 	/*
586 	 * {@inheritDoc}
587 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#setListenerReadCommunity(java.lang.String)
588 	 */
589 	public final void setListenerReadCommunity (final String listenerReadCommunity) {
590 		String newListenerReadCommunity = formatAttribute(listenerReadCommunity);
591 		if (newListenerReadCommunity == null) {
592 			newListenerReadCommunity = "public";
593 		}
594 		if (this.listenerReadCommunity != null ? !this.listenerReadCommunity.equals(newListenerReadCommunity) : true) {
595 			try {
596 				this.daemon.stop();
597 				this.jmxNotificationManager.setEnabled(false);
598 				this.listenerReadCommunity = newListenerReadCommunity;
599 			}
600 			catch (final Throwable e) {
601 				this.logger.error(e);
602 			}
603 		}
604 	}
605 
606 	/*
607 	 * {@inheritDoc}
608 	 * @see net.sf.snmpadaptor4j.api.SnmpDaemonConfiguration#getListenerWriteCommunity()
609 	 */
610 	public final String getListenerWriteCommunity () {
611 		return this.listenerWriteCommunity;
612 	}
613 
614 	/*
615 	 * {@inheritDoc}
616 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#setListenerWriteCommunity(java.lang.String)
617 	 */
618 	public final void setListenerWriteCommunity (final String listenerWriteCommunity) {
619 		String newListenerWriteCommunity = formatAttribute(listenerWriteCommunity);
620 		if (newListenerWriteCommunity == null) {
621 			newListenerWriteCommunity = "private";
622 		}
623 		if (this.listenerWriteCommunity != null ? !this.listenerWriteCommunity.equals(newListenerWriteCommunity) : true) {
624 			try {
625 				this.daemon.stop();
626 				this.jmxNotificationManager.setEnabled(false);
627 				this.listenerWriteCommunity = newListenerWriteCommunity;
628 			}
629 			catch (final Throwable e) {
630 				this.logger.error(e);
631 			}
632 		}
633 	}
634 
635 	/*
636 	 * {@inheritDoc}
637 	 * @see net.sf.snmpadaptor4j.SnmpConfiguration#getManagerList()
638 	 */
639 	public final List<SnmpManagerConfiguration> getManagerList () {
640 		return Collections.unmodifiableList(this.managerList);
641 	}
642 
643 	/*
644 	 * {@inheritDoc}
645 	 * @see net.sf.snmpadaptor4j.SnmpAppContext#getDefaultRootOid()
646 	 */
647 	public final String getDefaultRootOid () {
648 		return this.defaultRootOid;
649 	}
650 
651 	/*
652 	 * {@inheritDoc}
653 	 * @see net.sf.snmpadaptor4j.SnmpAppContext#getRootOidMap()
654 	 */
655 	public final Map<String, String> getRootOidMap () {
656 		return this.rootOidMap;
657 	}
658 
659 	/*
660 	 * {@inheritDoc}
661 	 * @see net.sf.snmpadaptor4j.SnmpAppContext#getMBeanOidMap()
662 	 */
663 	public final Map<ObjectName, String> getMBeanOidMap () {
664 		return this.mBeanOidMap;
665 	}
666 
667 	/*
668 	 * {@inheritDoc}
669 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#start()
670 	 */
671 	public void start () throws Exception {
672 		this.daemon.start();
673 		if (!this.daemon.isStarted()) {
674 			throw new Exception("The SNMP daemon did not start");
675 		}
676 		this.jmxNotificationManager.setEnabled(true);
677 	}
678 
679 	/*
680 	 * {@inheritDoc}
681 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#stop()
682 	 */
683 	public void stop () throws Exception {
684 		this.daemon.stop();
685 		if (this.daemon.isStarted()) {
686 			throw new Exception("The SNMP daemon has not been stopped");
687 		}
688 		this.jmxNotificationManager.setEnabled(false);
689 	}
690 
691 	/*
692 	 * {@inheritDoc}
693 	 * @see net.sf.snmpadaptor4j.SnmpAdaptorMBean#isStarted()
694 	 */
695 	public final boolean isStarted () {
696 		return this.daemon.isStarted();
697 	}
698 
699 	/**
700 	 * Returns the informations on the system.
701 	 * <p>
702 	 * The returned object is a MBean. It is possible to register it in JMX.
703 	 * </p>
704 	 * @return Informations on the system.
705 	 */
706 	public final SystemInfo getSystemInfo () {
707 		return this.systemInfo;
708 	}
709 
710 	/**
711 	 * Formats an attribute value.
712 	 * @param value Value to format.
713 	 * @return Value formatted.
714 	 */
715 	protected static final String formatAttribute (final String value) {
716 		String result = value;
717 		if (result != null) {
718 			result = result.trim();
719 			if (result.length() == 0) {
720 				result = null;
721 			}
722 		}
723 		return result;
724 	}
725 
726 	/*
727 	 * {@inheritDoc}
728 	 * @see javax.management.StandardMBean#preRegister(javax.management.MBeanServer, javax.management.ObjectName)
729 	 */
730 	@Override
731 	public ObjectName preRegister (final MBeanServer server, final ObjectName name) throws Exception {
732 		final ObjectName result = super.preRegister(server, name);
733 		this.jmxListener.open(server);
734 		this.jvmMib.open(server);
735 		return result;
736 	}
737 
738 	/*
739 	 * {@inheritDoc}
740 	 * @see javax.management.StandardMBean#preDeregister()
741 	 */
742 	@Override
743 	public void preDeregister () throws Exception {
744 		super.preDeregister();
745 		this.jmxListener.close();
746 		this.jvmMib.close();
747 	}
748 
749 	/*
750 	 * {@inheritDoc}
751 	 * @see java.lang.Object#toString()
752 	 */
753 	@Override
754 	public String toString () {
755 		return "SnmpAdaptor[" + this.listenerAddress + ":" + this.listenerPort + "]";
756 	}
757 
758 }