View Javadoc

1   package net.sf.snmpadaptor4j.core;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.List;
6   import java.util.Map;
7   import java.util.Map.Entry;
8   import javax.management.MBeanServer;
9   import javax.management.Notification;
10  import javax.management.NotificationListener;
11  import javax.management.ObjectName;
12  import org.apache.log4j.Logger;
13  import net.sf.snmpadaptor4j.core.mapping.SnmpTrapMapping;
14  import net.sf.snmpadaptor4j.core.trap.SnmpManagers;
15  import net.sf.snmpadaptor4j.core.trap.SnmpTrapBuilder;
16  import net.sf.snmpadaptor4j.mbean.SystemInfo;
17  import net.sf.snmpadaptor4j.object.SnmpTrap;
18  
19  /**
20   * Object responsible of:
21   * <ul>
22   * <li>the conversion of JMX notifications to SNMP traps,</li>
23   * <li>and the sending SNMP traps to SNMP managers.</li>
24   * </ul>
25   * @author <a href="http://fr.linkedin.com/in/jpminetti/">Jean-Philippe MINETTI</a>
26   */
27  public class JmxNotificationManager {
28  
29  	/**
30  	 * JMX notification listener.
31  	 */
32  	protected final class Listener
33  			implements NotificationListener {
34  
35  		/**
36  		 * Builder of SNMP traps from JMX notifications for an MBean.
37  		 */
38  		protected final SnmpTrapBuilder trapBuilder;
39  
40  		/**
41  		 * Constructor.
42  		 * @param trapBuilder Builder of SNMP traps from JMX notifications for an MBean (must not be <code>NULL</code>).
43  		 */
44  		protected Listener (final SnmpTrapBuilder trapBuilder) {
45  			super();
46  			this.trapBuilder = trapBuilder;
47  		}
48  
49  		/*
50  		 * {@inheritDoc}
51  		 * @see javax.management.NotificationListener#handleNotification(javax.management.Notification, java.lang.Object)
52  		 */
53  		public void handleNotification (final Notification notification, final Object handback) {
54  			JmxNotificationManager.this.handleNotification(this.trapBuilder, notification);
55  		}
56  
57  		/*
58  		 * {@inheritDoc}
59  		 * @see java.lang.Object#toString()
60  		 */
61  		@Override
62  		public String toString () {
63  			return "Listener[trapBuilder=" + this.trapBuilder + "]";
64  		}
65  
66  	}
67  
68  	/**
69  	 * Logger.
70  	 */
71  	protected final Logger logger = Logger.getLogger(JmxNotificationManager.class);
72  
73  	/**
74  	 * SNMP managers on the network to which SNMP traps should be sent.
75  	 */
76  	private final SnmpManagers managers;
77  
78  	/**
79  	 * Informations on the system.
80  	 */
81  	private final SystemInfo systemInfo;
82  
83  	/**
84  	 * Map of JMX notification listener for each registered MBean.
85  	 */
86  	protected final Map<ObjectName, Listener> listenerMap = new HashMap<ObjectName, Listener>();
87  
88  	/**
89  	 * <code>TRUE</code> to handle notifications, otherwise <code>FALSE</code> to ignore.
90  	 */
91  	private boolean enabled = false;
92  
93  	/**
94  	 * Constructor.
95  	 * @param managers SNMP managers on the network to which SNMP traps should be sent (must not be <code>NULL</code>).
96  	 * @param systemInfo Informations on the system.
97  	 */
98  	public JmxNotificationManager (final SnmpManagers managers, final SystemInfo systemInfo) {
99  		super();
100 		this.managers = managers;
101 		this.systemInfo = systemInfo;
102 	}
103 
104 	/**
105 	 * Registers a notification listener used for send SNMP traps from the JMX notifications.
106 	 * @param server JMX agent (must not be <code>NULL</code>).
107 	 * @param mBeanName MBean name (must not be <code>NULL</code>).
108 	 * @param trapMappingMap Map of mapping to build SNMP traps from the JMX notifications for each notification type (must not be <code>NULL</code>).
109 	 */
110 	synchronized void register (final MBeanServer server, final ObjectName mBeanName, final Map<String, SnmpTrapMapping> trapMappingMap) {
111 		if (trapMappingMap.isEmpty()) {
112 			if (this.logger.isDebugEnabled()) {
113 				this.logger.debug("None SNMP trap mapped for [" + mBeanName + "]");
114 			}
115 		}
116 		else {
117 			if (this.logger.isInfoEnabled()) {
118 				for (final Entry<String, SnmpTrapMapping> trapMappingEntry : trapMappingMap.entrySet()) {
119 					this.logger.info("MBean notification registered at [" + mBeanName + "].[" + trapMappingEntry.getKey() + "] = " + trapMappingEntry.getValue());
120 				}
121 			}
122 			final Listener listener = new Listener(new SnmpTrapBuilder(trapMappingMap, this.systemInfo));
123 			try {
124 				server.addNotificationListener(mBeanName, listener, null, null);
125 				this.listenerMap.put(mBeanName, listener);
126 			}
127 			catch (final Throwable e) {
128 				this.logger.warn("Notifications issued in on [" + mBeanName + "] will not cause any SNMP trap sending", e);
129 			}
130 		}
131 	}
132 
133 	/**
134 	 * Unregisters all notification listeners used for send SNMP traps from the JMX notifications.
135 	 * @param server JMX agent.
136 	 */
137 	synchronized void unregisterAll (final MBeanServer server) {
138 		final List<ObjectName> mBeanNameList = new ArrayList<ObjectName>(this.listenerMap.keySet());
139 		for (final ObjectName mBeanName : mBeanNameList) {
140 			unregister(server, mBeanName);
141 		}
142 	}
143 
144 	/**
145 	 * Unregisters a notification listener used for send SNMP traps from the JMX notifications.
146 	 * @param server JMX agent.
147 	 * @param mBeanName MBean name.
148 	 */
149 	synchronized void unregister (final MBeanServer server, final ObjectName mBeanName) {
150 		final Listener listener = this.listenerMap.get(mBeanName);
151 		if (listener != null) {
152 			if (this.logger.isInfoEnabled()) {
153 				for (final String notificationType : listener.trapBuilder.getMappingMap().keySet()) {
154 					this.logger.info("MBean notification unregistered at [" + mBeanName + "].[" + notificationType + "]");
155 				}
156 			}
157 			try {
158 				if (server.isRegistered(mBeanName)) {
159 					server.removeNotificationListener(mBeanName, listener);
160 				}
161 				else {
162 					if (this.logger.isTraceEnabled()) {
163 						this.logger.trace("[" + mBeanName + "] already unregistered from JMX");
164 					}
165 				}
166 				this.listenerMap.remove(mBeanName);
167 			}
168 			catch (final Throwable e) {
169 				this.logger.warn("An error occurred when unloading of [" + mBeanName + "] to support notifications", e);
170 			}
171 		}
172 	}
173 
174 	/**
175 	 * Returns <code>TRUE</code> to handle notifications, or <code>FALSE</code> to ignore.
176 	 * @return <code>TRUE</code> to handle notifications.
177 	 */
178 	public final boolean isEnabled () {
179 		return this.enabled;
180 	}
181 
182 	/**
183 	 * Sets <code>TRUE</code> to handle notifications, or <code>FALSE</code> to ignore.
184 	 * @param enabled <code>TRUE</code> to handle notifications.
185 	 */
186 	public void setEnabled (boolean enabled) {
187 		this.enabled = enabled;
188 	}
189 
190 	/**
191 	 * Handles a JMX notification from an MBean.
192 	 * @param trapBuilder Builder of SNMP traps from JMX notifications for an MBean.
193 	 * @param notification JMX notification.
194 	 */
195 	protected final void handleNotification (final SnmpTrapBuilder trapBuilder, final Notification notification) {
196 		if (this.enabled) {
197 			if (this.logger.isTraceEnabled()) {
198 				this.logger.trace("JMX notification [" + notification.getSource() + "].[" + notification.getType() + "] received");
199 				this.logger.trace("source           = " + notification.getSource());
200 				this.logger.trace("sequenceNumber   = " + notification.getSequenceNumber());
201 				this.logger.trace("timeStamp        = " + notification.getTimeStamp());
202 				this.logger.trace("type             = " + notification.getType());
203 				this.logger.trace("message          = " + notification.getMessage());
204 				if (notification.getUserData() instanceof Map) {
205 					for (final Entry<?, ?> entry : ((Map<?, ?>) (notification.getUserData())).entrySet()) {
206 						this.logger.trace("userData:        " + entry.getKey() + " = " + entry.getValue());
207 					}
208 				}
209 				else {
210 					this.logger.trace("userData         = "
211 							+ (notification.getUserData() != null ? "(" + notification.getUserData().getClass().getName() + ")" : "") + notification.getUserData());
212 				}
213 			}
214 			try {
215 				final SnmpTrap trap = trapBuilder.newTrap(notification);
216 				if (trap == null) {
217 					if (this.logger.isDebugEnabled()) {
218 						this.logger.debug("None SNMP trap to send for the JMX notification [" + notification.getSource() + "].[" + notification.getType() + "]");
219 					}
220 				}
221 				else {
222 					if (this.logger.isDebugEnabled()) {
223 						this.logger.debug("Notification [" + notification.getSource() + "].[" + notification.getType() + "] = " + trap);
224 					}
225 					this.managers.send(trap);
226 				}
227 			}
228 			catch (final Throwable e) {
229 				this.logger.error("Unable to handle the notification " + notification + " for send a SNMP trap", e);
230 			}
231 		}
232 	}
233 
234 	/*
235 	 * {@inheritDoc}
236 	 * @see java.lang.Object#toString()
237 	 */
238 	@Override
239 	public final String toString () {
240 		return "JmxNotificationManager[managers=" + this.managers + "; systemInfo=" + this.systemInfo + "; listenerMap=" + this.listenerMap + "]";
241 	}
242 
243 }