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.core; 028 import org.opends.messages.Message; 029 030 031 032 import java.lang.reflect.Method; 033 import java.util.ArrayList; 034 import java.util.Iterator; 035 import java.util.List; 036 import java.util.concurrent.ConcurrentHashMap; 037 038 import org.opends.server.admin.ClassPropertyDefinition; 039 import org.opends.server.admin.server.ConfigurationAddListener; 040 import org.opends.server.admin.server.ConfigurationChangeListener; 041 import org.opends.server.admin.server.ConfigurationDeleteListener; 042 import org.opends.server.admin.std.meta.AlertHandlerCfgDefn; 043 import org.opends.server.admin.std.server.AlertHandlerCfg; 044 import org.opends.server.admin.std.server.RootCfg; 045 import org.opends.server.admin.server.ServerManagementContext; 046 import org.opends.server.api.AlertHandler; 047 import org.opends.server.config.ConfigException; 048 import org.opends.server.types.ConfigChangeResult; 049 import org.opends.server.types.DN; 050 051 052 import org.opends.server.types.InitializationException; 053 import org.opends.server.types.ResultCode; 054 055 import static org.opends.messages.ConfigMessages.*; 056 057 import static org.opends.server.util.StaticUtils.*; 058 import org.opends.server.loggers.ErrorLogger; 059 060 061 /** 062 * This class defines a utility that will be used to manage the set of alert 063 * handlers defined in the Directory Server. It will initialize the alert 064 * handlers when the server starts, and then will manage any additions, 065 * removals, or modifications to any alert handlers while the server is running. 066 */ 067 public class AlertHandlerConfigManager 068 implements ConfigurationChangeListener<AlertHandlerCfg>, 069 ConfigurationAddListener<AlertHandlerCfg>, 070 ConfigurationDeleteListener<AlertHandlerCfg> 071 072 { 073 // A mapping between the DNs of the config entries and the associated alert 074 // handlers. 075 private ConcurrentHashMap<DN,AlertHandler> alertHandlers; 076 077 078 079 /** 080 * Creates a new instance of this alert handler config manager. 081 */ 082 public AlertHandlerConfigManager() 083 { 084 alertHandlers = new ConcurrentHashMap<DN,AlertHandler>(); 085 } 086 087 088 089 /** 090 * Initializes all alert handlers currently defined in the Directory Server 091 * configuration. This should only be called at Directory Server startup. 092 * 093 * @throws ConfigException If a configuration problem causes the alert 094 * handler initialization process to fail. 095 * 096 * @throws InitializationException If a problem occurs while initializing 097 * the alert handlers that is not related to 098 * the server configuration. 099 */ 100 public void initializeAlertHandlers() 101 throws ConfigException, InitializationException 102 { 103 // Get the root configuration object. 104 ServerManagementContext managementContext = 105 ServerManagementContext.getInstance(); 106 RootCfg rootConfiguration = managementContext.getRootConfiguration(); 107 108 109 // Register as an add and delete listener with the root configuration so we 110 // can be notified if any alert handler entries are added or removed. 111 rootConfiguration.addAlertHandlerAddListener(this); 112 rootConfiguration.addAlertHandlerDeleteListener(this); 113 114 115 //Initialize the existing alert handlers. 116 for (String name : rootConfiguration.listAlertHandlers()) 117 { 118 AlertHandlerCfg configuration = rootConfiguration.getAlertHandler(name); 119 configuration.addChangeListener(this); 120 121 if (configuration.isEnabled()) 122 { 123 String className = configuration.getJavaClass(); 124 try 125 { 126 AlertHandler handler = loadHandler(className, configuration, true); 127 alertHandlers.put(configuration.dn(), handler); 128 DirectoryServer.registerAlertHandler(handler); 129 } 130 catch (InitializationException ie) 131 { 132 ErrorLogger.logError(ie.getMessageObject()); 133 continue; 134 } 135 } 136 } 137 } 138 139 140 141 /** 142 * {@inheritDoc} 143 */ 144 public boolean isConfigurationAddAcceptable(AlertHandlerCfg configuration, 145 List<Message> unacceptableReasons) 146 { 147 if (configuration.isEnabled()) 148 { 149 // Get the name of the class and make sure we can instantiate it as an 150 // alert handler. 151 String className = configuration.getJavaClass(); 152 try 153 { 154 loadHandler(className, configuration, false); 155 } 156 catch (InitializationException ie) 157 { 158 unacceptableReasons.add(ie.getMessageObject()); 159 return false; 160 } 161 } 162 163 // If we've gotten here, then it's fine. 164 return true; 165 } 166 167 168 169 /** 170 * {@inheritDoc} 171 */ 172 public ConfigChangeResult applyConfigurationAdd(AlertHandlerCfg configuration) 173 { 174 ResultCode resultCode = ResultCode.SUCCESS; 175 boolean adminActionRequired = false; 176 ArrayList<Message> messages = new ArrayList<Message>(); 177 178 configuration.addChangeListener(this); 179 180 if (! configuration.isEnabled()) 181 { 182 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 183 } 184 185 AlertHandler alertHandler = null; 186 187 // Get the name of the class and make sure we can instantiate it as an alert 188 // handler. 189 String className = configuration.getJavaClass(); 190 try 191 { 192 alertHandler = loadHandler(className, configuration, true); 193 } 194 catch (InitializationException ie) 195 { 196 if (resultCode == ResultCode.SUCCESS) 197 { 198 resultCode = DirectoryServer.getServerErrorResultCode(); 199 } 200 201 messages.add(ie.getMessageObject()); 202 } 203 204 if (resultCode == ResultCode.SUCCESS) 205 { 206 alertHandlers.put(configuration.dn(), alertHandler); 207 DirectoryServer.registerAlertHandler(alertHandler); 208 } 209 210 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 211 } 212 213 214 215 /** 216 * {@inheritDoc} 217 */ 218 public boolean isConfigurationDeleteAcceptable( 219 AlertHandlerCfg configuration, 220 List<Message> unacceptableReasons) 221 { 222 // FIXME -- We should try to perform some check to determine whether the 223 // alert handler is in use. 224 return true; 225 } 226 227 228 229 /** 230 * {@inheritDoc} 231 */ 232 public ConfigChangeResult applyConfigurationDelete( 233 AlertHandlerCfg configuration) 234 { 235 ResultCode resultCode = ResultCode.SUCCESS; 236 boolean adminActionRequired = false; 237 ArrayList<Message> messages = new ArrayList<Message>(); 238 239 AlertHandler alertHandler = alertHandlers.remove(configuration.dn()); 240 if (alertHandler != null) 241 { 242 DirectoryServer.deregisterAlertHandler(alertHandler); 243 alertHandler.finalizeAlertHandler(); 244 } 245 246 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 247 } 248 249 250 251 /** 252 * {@inheritDoc} 253 */ 254 public boolean isConfigurationChangeAcceptable(AlertHandlerCfg configuration, 255 List<Message> unacceptableReasons) 256 { 257 if (configuration.isEnabled()) 258 { 259 // Get the name of the class and make sure we can instantiate it as an 260 // alert handler. 261 String className = configuration.getJavaClass(); 262 try 263 { 264 loadHandler(className, configuration, false); 265 } 266 catch (InitializationException ie) 267 { 268 unacceptableReasons.add(ie.getMessageObject()); 269 return false; 270 } 271 } 272 273 // If we've gotten here, then it's fine. 274 return true; 275 } 276 277 278 279 /** 280 * {@inheritDoc} 281 */ 282 public ConfigChangeResult applyConfigurationChange( 283 AlertHandlerCfg configuration) 284 { 285 ResultCode resultCode = ResultCode.SUCCESS; 286 boolean adminActionRequired = false; 287 ArrayList<Message> messages = new ArrayList<Message>(); 288 289 290 // Get the existing alert handler if it's already enabled. 291 AlertHandler existingHandler = alertHandlers.get(configuration.dn()); 292 293 294 // If the new configuration has the handler disabled, then disable it if it 295 // is enabled, or do nothing if it's already disabled. 296 if (! configuration.isEnabled()) 297 { 298 if (existingHandler != null) 299 { 300 DirectoryServer.deregisterAlertHandler(existingHandler); 301 302 AlertHandler alertHandler = alertHandlers.remove(configuration.dn()); 303 if (alertHandler != null) 304 { 305 alertHandler.finalizeAlertHandler(); 306 } 307 } 308 309 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 310 } 311 312 313 // Get the class for the alert handler. If the handler is already enabled, 314 // then we shouldn't do anything with it although if the class has changed 315 // then we'll at least need to indicate that administrative action is 316 // required. If the handler is disabled, then instantiate the class and 317 // initialize and register it as an alert handler. 318 String className = configuration.getJavaClass(); 319 if (existingHandler != null) 320 { 321 if (! className.equals(existingHandler.getClass().getName())) 322 { 323 adminActionRequired = true; 324 } 325 326 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 327 } 328 329 AlertHandler alertHandler = null; 330 try 331 { 332 alertHandler = loadHandler(className, configuration, true); 333 } 334 catch (InitializationException ie) 335 { 336 if (resultCode == ResultCode.SUCCESS) 337 { 338 resultCode = DirectoryServer.getServerErrorResultCode(); 339 } 340 341 messages.add(ie.getMessageObject()); 342 } 343 344 if (resultCode == ResultCode.SUCCESS) 345 { 346 alertHandlers.put(configuration.dn(), alertHandler); 347 DirectoryServer.registerAlertHandler(alertHandler); 348 } 349 350 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 351 } 352 353 354 355 /** 356 * Loads the specified class, instantiates it as an alert handler, and 357 * optionally initializes that instance. 358 * 359 * @param className The fully-qualified name of the alert handler class 360 * to load, instantiate, and initialize. 361 * @param configuration The configuration to use to initialize the alert 362 * handler. It must not be {@code null}. 363 * @param initialize Indicates whether the alert handler instance should 364 * be initialized. 365 * 366 * @return The possibly initialized alert handler. 367 * 368 * @throws InitializationException If a problem occurred while attempting to 369 * initialize the alert handler. 370 */ 371 private AlertHandler loadHandler(String className, 372 AlertHandlerCfg configuration, 373 boolean initialize) 374 throws InitializationException 375 { 376 try 377 { 378 AlertHandlerCfgDefn definition = AlertHandlerCfgDefn.getInstance(); 379 ClassPropertyDefinition propertyDefinition = 380 definition.getJavaClassPropertyDefinition(); 381 Class<? extends AlertHandler> handlerClass = 382 propertyDefinition.loadClass(className, AlertHandler.class); 383 AlertHandler handler = handlerClass.newInstance(); 384 385 if (initialize) 386 { 387 Method method = handler.getClass().getMethod("initializeAlertHandler", 388 configuration.configurationClass()); 389 method.invoke(handler, configuration); 390 } 391 else 392 { 393 Method method = 394 handler.getClass().getMethod("isConfigurationAcceptable", 395 AlertHandlerCfg.class, List.class); 396 397 List<Message> unacceptableReasons = new ArrayList<Message>(); 398 Boolean acceptable = (Boolean) method.invoke(handler, configuration, 399 unacceptableReasons); 400 if (! acceptable) 401 { 402 StringBuilder buffer = new StringBuilder(); 403 if (! unacceptableReasons.isEmpty()) 404 { 405 Iterator<Message> iterator = unacceptableReasons.iterator(); 406 buffer.append(iterator.next()); 407 while (iterator.hasNext()) 408 { 409 buffer.append(". "); 410 buffer.append(iterator.next()); 411 } 412 } 413 414 Message message = ERR_CONFIG_ALERTHANDLER_CONFIG_NOT_ACCEPTABLE.get( 415 String.valueOf(configuration.dn()), buffer.toString()); 416 throw new InitializationException(message); 417 } 418 } 419 420 return handler; 421 } 422 catch (Exception e) 423 { 424 Message message = ERR_CONFIG_ALERTHANDLER_INITIALIZATION_FAILED. 425 get(className, String.valueOf(configuration.dn()), 426 stackTraceToSingleLineString(e)); 427 throw new InitializationException(message, e); 428 } 429 } 430 } 431