001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.extensions;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033 import java.util.List;
034 import java.util.concurrent.ConcurrentHashMap;
035 import java.util.concurrent.atomic.AtomicLong;
036 import javax.management.Attribute;
037 import javax.management.AttributeList;
038 import javax.management.AttributeNotFoundException;
039 import javax.management.DynamicMBean;
040 import javax.management.InvalidAttributeValueException;
041 import javax.management.MBeanAttributeInfo;
042 import javax.management.MBeanConstructorInfo;
043 import javax.management.MBeanException;
044 import javax.management.MBeanInfo;
045 import javax.management.MBeanNotificationInfo;
046 import javax.management.MBeanOperationInfo;
047 import javax.management.MBeanServer;
048 import javax.management.Notification;
049 import javax.management.NotificationBroadcasterSupport;
050 import javax.management.ObjectName;
051
052 import org.opends.server.admin.server.ConfigurationChangeListener;
053 import org.opends.server.admin.std.server.AlertHandlerCfg;
054 import org.opends.server.admin.std.server.JMXAlertHandlerCfg;
055 import org.opends.server.api.AlertGenerator;
056 import org.opends.server.api.AlertHandler;
057 import org.opends.server.api.DirectoryServerMBean;
058 import org.opends.server.config.ConfigException;
059 import org.opends.server.config.JMXMBean;
060 import org.opends.server.core.DirectoryServer;
061 import org.opends.server.loggers.debug.DebugTracer;
062 import org.opends.server.types.ConfigChangeResult;
063 import org.opends.server.types.DebugLogLevel;
064 import org.opends.server.types.DN;
065 import org.opends.server.types.InitializationException;
066 import org.opends.server.types.ResultCode;
067
068 import static org.opends.server.loggers.debug.DebugLogger.*;
069 import static org.opends.messages.ConfigMessages.*;
070 import static org.opends.messages.ExtensionMessages.*;
071
072 import static org.opends.server.util.ServerConstants.*;
073
074
075
076 /**
077 * This class provides an implementation of a Directory Server alert handler
078 * that will send alerts using JMX notifications.
079 */
080 public class JMXAlertHandler
081 extends NotificationBroadcasterSupport
082 implements AlertHandler<JMXAlertHandlerCfg>,
083 ConfigurationChangeListener<JMXAlertHandlerCfg>, DynamicMBean,
084 DirectoryServerMBean
085 {
086 /**
087 * The tracer object for the debug logger.
088 */
089 private static final DebugTracer TRACER = getTracer();
090
091 /**
092 * The fully-qualified name of this class.
093 */
094 private static final String CLASS_NAME =
095 "org.opends.server.extensions.JMXAlertHandler";
096
097
098
099 // The current configuration for this alert handler.
100 private AlertHandlerCfg currentConfig;
101
102 // The sequence number generator used for this alert handler.
103 private AtomicLong sequenceNumber;
104
105 // The DN of the configuration entry with which this alert handler is
106 // associated.
107 private DN configEntryDN;
108
109 // The JMX object name used for this JMX alert handler.
110 private ObjectName objectName;
111
112
113
114 /**
115 * Creates a new instance of this JMX alert handler. No initialization should
116 * be done here, as it should all be performed in the
117 * <CODE>initializeAlertHandler</CODE> method.
118 */
119 public JMXAlertHandler()
120 {
121 super();
122 }
123
124
125
126 /**
127 * {@inheritDoc}
128 */
129 public void initializeAlertHandler(JMXAlertHandlerCfg configuration)
130 throws ConfigException, InitializationException
131 {
132 sequenceNumber = new AtomicLong(1);
133
134 if (configuration == null)
135 {
136 configEntryDN = null;
137 }
138 else
139 {
140 configEntryDN = configuration.dn();
141 }
142
143 MBeanServer mBeanServer = DirectoryServer.getJMXMBeanServer();
144 if (mBeanServer != null)
145 {
146 try
147 {
148 String nameStr = MBEAN_BASE_DOMAIN + ":type=JMXAlertHandler";
149 objectName = new ObjectName(nameStr);
150 if (mBeanServer.isRegistered(objectName))
151 {
152 mBeanServer.unregisterMBean(objectName);
153 }
154
155 mBeanServer.registerMBean(this, objectName);
156 }
157 catch (Exception e)
158 {
159 if (debugEnabled())
160 {
161 TRACER.debugCaught(DebugLogLevel.ERROR, e);
162 }
163
164 Message message =
165 ERR_JMX_ALERT_HANDLER_CANNOT_REGISTER.get(String.valueOf(e));
166 throw new InitializationException(message, e);
167 }
168 }
169
170 if (configuration != null)
171 {
172 configuration.addJMXChangeListener(this);
173 currentConfig = configuration;
174 }
175 }
176
177
178
179 /**
180 * {@inheritDoc}
181 */
182 public AlertHandlerCfg getAlertHandlerConfiguration()
183 {
184 return currentConfig;
185 }
186
187
188
189 /**
190 * {@inheritDoc}
191 */
192 public boolean isConfigurationAcceptable(AlertHandlerCfg configuration,
193 List<Message> unacceptableReasons)
194 {
195 JMXAlertHandlerCfg cfg = (JMXAlertHandlerCfg) configuration;
196 return isConfigurationChangeAcceptable(cfg, unacceptableReasons);
197 }
198
199
200
201 /**
202 * {@inheritDoc}
203 */
204 public void finalizeAlertHandler()
205 {
206 // No action is required.
207 }
208
209
210
211 /**
212 * Retrieves the JMX object name for this JMX alert handler.
213 *
214 * @return The JMX object name for this JMX alert handler.
215 */
216 public ObjectName getObjectName()
217 {
218 return objectName;
219 }
220
221
222
223 /**
224 * {@inheritDoc}
225 */
226 public void sendAlertNotification(AlertGenerator generator, String alertType,
227 Message alertMessage)
228 {
229 sendNotification(new Notification(alertType, generator.getClassName(),
230 sequenceNumber.getAndIncrement(),
231 System.currentTimeMillis(),
232 alertMessage.toString()));
233 }
234
235
236
237 /**
238 * Retrieves information about the types of JMX notifications that may be
239 * generated.
240 *
241 * @return Information about the types of JMX notifications that may be
242 * generated.
243 */
244 public MBeanNotificationInfo[] getNotificationInfo()
245 {
246 ArrayList<MBeanNotificationInfo> notifications =
247 new ArrayList<MBeanNotificationInfo>();
248 ConcurrentHashMap<DN,JMXMBean> mBeans = DirectoryServer.getJMXMBeans();
249 for (JMXMBean mBean : mBeans.values())
250 {
251 MBeanInfo mBeanInfo = mBean.getMBeanInfo();
252 for (MBeanNotificationInfo notification: mBeanInfo.getNotifications())
253 {
254 notifications.add(notification);
255 }
256 }
257
258 MBeanNotificationInfo[] notificationArray =
259 new MBeanNotificationInfo[notifications.size()];
260 notifications.toArray(notificationArray);
261 return notificationArray;
262 }
263
264
265
266 /**
267 * Obtain the value of a specific attribute of the Dynamic MBean.
268 *
269 * @param attribute The name of the attribute to be retrieved.
270 *
271 * @return The requested MBean attribute.
272 *
273 * @throws AttributeNotFoundException If the specified attribute is not
274 * associated with this MBean.
275 */
276 public Attribute getAttribute(String attribute)
277 throws AttributeNotFoundException
278 {
279 // There are no attributes for this MBean.
280 Message message = ERR_CONFIG_JMX_ATTR_NO_ATTR.get(
281 String.valueOf(configEntryDN), attribute);
282 throw new AttributeNotFoundException(message.toString());
283 }
284
285
286
287 /**
288 * Set the value of a specific attribute of the Dynamic MBean.
289 *
290 * @param attribute The identification of the attribute to be set and the
291 * value it is to be set to.
292 *
293 * @throws AttributeNotFoundException If the specified attribute is not
294 * associated with this MBean.
295 *
296 * @throws InvalidAttributeValueException If the provided value is not
297 * acceptable for this MBean.
298 */
299 public void setAttribute(Attribute attribute)
300 throws AttributeNotFoundException, InvalidAttributeValueException
301 {
302 // There are no attributes for this MBean.
303 Message message = ERR_CONFIG_JMX_ATTR_NO_ATTR.get(
304 String.valueOf(configEntryDN), String.valueOf(attribute));
305 throw new AttributeNotFoundException(message.toString());
306 }
307
308
309
310 /**
311 * Get the values of several attributes of the Dynamic MBean.
312 *
313 * @param attributes A list of the attributes to be retrieved.
314 *
315 * @return The list of attributes retrieved.
316 */
317 public AttributeList getAttributes(String[] attributes)
318 {
319 // There are no attributes for this MBean.
320 return new AttributeList();
321 }
322
323
324
325 /**
326 * Sets the values of several attributes of the Dynamic MBean.
327 *
328 * @param attributes A list of attributes: The identification of the
329 * attributes to be set and the values they are to be set
330 * to.
331 *
332 * @return The list of attributes that were set with their new values.
333 */
334 public AttributeList setAttributes(AttributeList attributes)
335 {
336 // There are no attributes for this MBean.
337 return new AttributeList();
338 }
339
340
341
342 /**
343 * Allows an action to be invoked on the Dynamic MBean.
344 *
345 * @param actionName The name of the action to be invoked.
346 * @param params An array containing the parameters to be set when the
347 * action is invoked.
348 * @param signature An array containing the signature of the action. The
349 * class objects will be loaded through the same class
350 * loader as the one used for loading the MBean on which
351 * action is invoked.
352 *
353 * @return The object returned by the action, which represents the result of
354 * invoking the action on the MBean specified.
355 *
356 * @throws MBeanException If a problem is encountered while invoking the
357 * method.
358 */
359 public Object invoke(String actionName, Object[] params, String[] signature)
360 throws MBeanException
361 {
362 // There are no invokable components for this MBean.
363 StringBuilder buffer = new StringBuilder();
364 buffer.append(actionName);
365 buffer.append("(");
366
367 if (signature.length > 0)
368 {
369 buffer.append(signature[0]);
370
371 for (int i=1; i < signature.length; i++)
372 {
373 buffer.append(", ");
374 buffer.append(signature[i]);
375 }
376 }
377
378 buffer.append(")");
379
380 Message message = ERR_CONFIG_JMX_NO_METHOD.get(
381 buffer.toString(), String.valueOf(configEntryDN));
382 throw new MBeanException(new ConfigException(message));
383 }
384
385
386
387 /**
388 * Provides the exposed attributes and actions of the Dynamic MBean using an
389 * MBeanInfo object.
390 *
391 * @return An instance of <CODE>MBeanInfo</CODE> allowing all attributes and
392 * actions exposed by this Dynamic MBean to be retrieved.
393 */
394 public MBeanInfo getMBeanInfo()
395 {
396 return new MBeanInfo(CLASS_NAME, "JMX Alert Handler",
397 new MBeanAttributeInfo[0], new MBeanConstructorInfo[0],
398 new MBeanOperationInfo[0], getNotificationInfo());
399 }
400
401
402
403 /**
404 * {@inheritDoc}
405 */
406 public boolean isConfigurationChangeAcceptable(
407 JMXAlertHandlerCfg configuration,
408 List<Message> unacceptableReasons)
409 {
410 return true;
411 }
412
413
414
415 /**
416 * {@inheritDoc}
417 */
418 public ConfigChangeResult applyConfigurationChange(
419 JMXAlertHandlerCfg configuration)
420 {
421 currentConfig = configuration;
422
423 return new ConfigChangeResult(ResultCode.SUCCESS, false);
424 }
425 }
426