001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.core; 018 019import java.util.ArrayList; 020import java.util.List; 021import java.util.concurrent.ConcurrentHashMap; 022 023import org.forgerock.i18n.LocalizableMessage; 024import org.forgerock.i18n.slf4j.LocalizedLogger; 025import org.forgerock.opendj.config.ClassPropertyDefinition; 026import org.forgerock.opendj.config.server.ConfigChangeResult; 027import org.forgerock.opendj.config.server.ConfigException; 028import org.forgerock.opendj.config.server.ConfigurationAddListener; 029import org.forgerock.opendj.config.server.ConfigurationChangeListener; 030import org.forgerock.opendj.config.server.ConfigurationDeleteListener; 031import org.forgerock.opendj.ldap.DN; 032import org.forgerock.opendj.ldap.ResultCode; 033import org.forgerock.opendj.server.config.meta.AlertHandlerCfgDefn; 034import org.forgerock.opendj.server.config.server.AlertHandlerCfg; 035import org.forgerock.opendj.server.config.server.RootCfg; 036import org.forgerock.util.Utils; 037import org.opends.server.api.AlertHandler; 038import org.opends.server.types.InitializationException; 039 040import static org.opends.messages.ConfigMessages.*; 041import static org.opends.server.util.StaticUtils.*; 042 043/** 044 * This class defines a utility that will be used to manage the set of alert 045 * handlers defined in the Directory Server. It will initialize the alert 046 * handlers when the server starts, and then will manage any additions, 047 * removals, or modifications to any alert handlers while the server is running. 048 */ 049public class AlertHandlerConfigManager 050 implements ConfigurationChangeListener<AlertHandlerCfg>, 051 ConfigurationAddListener<AlertHandlerCfg>, 052 ConfigurationDeleteListener<AlertHandlerCfg> 053{ 054 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 055 056 /** A mapping between the DNs of the config entries and the associated alert handlers. */ 057 private final ConcurrentHashMap<DN, AlertHandler<?>> alertHandlers; 058 059 private final ServerContext serverContext; 060 061 /** 062 * Creates a new instance of this alert handler config manager. 063 * 064 * @param serverContext 065 * The server context. 066 */ 067 public AlertHandlerConfigManager(ServerContext serverContext) 068 { 069 this.serverContext = serverContext; 070 alertHandlers = new ConcurrentHashMap<>(); 071 } 072 073 /** 074 * Initializes all alert handlers currently defined in the Directory Server 075 * configuration. This should only be called at Directory Server startup. 076 * 077 * @throws ConfigException If a configuration problem causes the alert 078 * handler initialization process to fail. 079 * 080 * @throws InitializationException If a problem occurs while initializing 081 * the alert handlers that is not related to 082 * the server configuration. 083 */ 084 public void initializeAlertHandlers() 085 throws ConfigException, InitializationException 086 { 087 RootCfg rootConfiguration = serverContext.getRootConfig(); 088 rootConfiguration.addAlertHandlerAddListener(this); 089 rootConfiguration.addAlertHandlerDeleteListener(this); 090 091 //Initialize the existing alert handlers. 092 for (String name : rootConfiguration.listAlertHandlers()) 093 { 094 AlertHandlerCfg configuration = rootConfiguration.getAlertHandler(name); 095 configuration.addChangeListener(this); 096 097 if (configuration.isEnabled()) 098 { 099 String className = configuration.getJavaClass(); 100 try 101 { 102 AlertHandler<?> handler = loadHandler(className, configuration, true); 103 alertHandlers.put(configuration.dn(), handler); 104 DirectoryServer.registerAlertHandler(handler); 105 } 106 catch (InitializationException ie) 107 { 108 logger.error(ie.getMessageObject()); 109 continue; 110 } 111 } 112 } 113 } 114 115 @Override 116 public boolean isConfigurationAddAcceptable(AlertHandlerCfg configuration, 117 List<LocalizableMessage> unacceptableReasons) 118 { 119 if (configuration.isEnabled()) 120 { 121 // Get the name of the class and make sure we can instantiate it as an 122 // alert handler. 123 String className = configuration.getJavaClass(); 124 try 125 { 126 loadHandler(className, configuration, false); 127 } 128 catch (InitializationException ie) 129 { 130 unacceptableReasons.add(ie.getMessageObject()); 131 return false; 132 } 133 } 134 135 // If we've gotten here, then it's fine. 136 return true; 137 } 138 139 @Override 140 public ConfigChangeResult applyConfigurationAdd(AlertHandlerCfg configuration) 141 { 142 final ConfigChangeResult ccr = new ConfigChangeResult(); 143 144 configuration.addChangeListener(this); 145 146 if (! configuration.isEnabled()) 147 { 148 return ccr; 149 } 150 151 AlertHandler<?> alertHandler = null; 152 153 // Get the name of the class and make sure we can instantiate it as an alert handler 154 String className = configuration.getJavaClass(); 155 try 156 { 157 alertHandler = loadHandler(className, configuration, true); 158 } 159 catch (InitializationException ie) 160 { 161 ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode()); 162 ccr.addMessage(ie.getMessageObject()); 163 } 164 165 if (ccr.getResultCode() == ResultCode.SUCCESS) 166 { 167 alertHandlers.put(configuration.dn(), alertHandler); 168 DirectoryServer.registerAlertHandler(alertHandler); 169 } 170 171 return ccr; 172 } 173 174 @Override 175 public boolean isConfigurationDeleteAcceptable( 176 AlertHandlerCfg configuration, 177 List<LocalizableMessage> unacceptableReasons) 178 { 179 // FIXME -- We should try to perform some check to determine whether the 180 // alert handler is in use. 181 return true; 182 } 183 184 @Override 185 public ConfigChangeResult applyConfigurationDelete( 186 AlertHandlerCfg configuration) 187 { 188 final ConfigChangeResult ccr = new ConfigChangeResult(); 189 190 AlertHandler<?> alertHandler = alertHandlers.remove(configuration.dn()); 191 if (alertHandler != null) 192 { 193 DirectoryServer.deregisterAlertHandler(alertHandler); 194 alertHandler.finalizeAlertHandler(); 195 } 196 197 return ccr; 198 } 199 200 @Override 201 public boolean isConfigurationChangeAcceptable(AlertHandlerCfg configuration, 202 List<LocalizableMessage> unacceptableReasons) 203 { 204 if (configuration.isEnabled()) 205 { 206 // Get the name of the class and make sure we can instantiate it as an 207 // alert handler. 208 String className = configuration.getJavaClass(); 209 try 210 { 211 loadHandler(className, configuration, false); 212 } 213 catch (InitializationException ie) 214 { 215 unacceptableReasons.add(ie.getMessageObject()); 216 return false; 217 } 218 } 219 220 // If we've gotten here, then it's fine. 221 return true; 222 } 223 224 @Override 225 public ConfigChangeResult applyConfigurationChange( 226 AlertHandlerCfg configuration) 227 { 228 final ConfigChangeResult ccr = new ConfigChangeResult(); 229 230 // Get the existing alert handler if it's already enabled. 231 AlertHandler<?> existingHandler = alertHandlers.get(configuration.dn()); 232 233 // If the new configuration has the handler disabled, then disable it if it 234 // is enabled, or do nothing if it's already disabled. 235 if (! configuration.isEnabled()) 236 { 237 if (existingHandler != null) 238 { 239 DirectoryServer.deregisterAlertHandler(existingHandler); 240 241 AlertHandler<?> alertHandler = alertHandlers.remove(configuration.dn()); 242 if (alertHandler != null) 243 { 244 alertHandler.finalizeAlertHandler(); 245 } 246 } 247 248 return ccr; 249 } 250 251 // Get the class for the alert handler. If the handler is already enabled, 252 // then we shouldn't do anything with it although if the class has changed 253 // then we'll at least need to indicate that administrative action is 254 // required. If the handler is disabled, then instantiate the class and 255 // initialize and register it as an alert handler. 256 String className = configuration.getJavaClass(); 257 if (existingHandler != null) 258 { 259 if (! className.equals(existingHandler.getClass().getName())) 260 { 261 ccr.setAdminActionRequired(true); 262 } 263 264 return ccr; 265 } 266 267 AlertHandler<?> alertHandler = null; 268 try 269 { 270 alertHandler = loadHandler(className, configuration, true); 271 } 272 catch (InitializationException ie) 273 { 274 ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode()); 275 ccr.addMessage(ie.getMessageObject()); 276 } 277 278 if (ccr.getResultCode() == ResultCode.SUCCESS) 279 { 280 alertHandlers.put(configuration.dn(), alertHandler); 281 DirectoryServer.registerAlertHandler(alertHandler); 282 } 283 284 return ccr; 285 } 286 287 /** 288 * Loads the specified class, instantiates it as an alert handler, and 289 * optionally initializes that instance. 290 * 291 * @param className The fully-qualified name of the alert handler class 292 * to load, instantiate, and initialize. 293 * @param configuration The configuration to use to initialize the alert 294 * handler. It must not be {@code null}. 295 * @param initialize Indicates whether the alert handler instance should 296 * be initialized. 297 * 298 * @return The possibly initialized alert handler. 299 * 300 * @throws InitializationException If a problem occurred while attempting to 301 * initialize the alert handler. 302 */ 303 private AlertHandler<?> loadHandler(String className, 304 AlertHandlerCfg configuration, 305 boolean initialize) 306 throws InitializationException 307 { 308 try 309 { 310 AlertHandlerCfgDefn definition = AlertHandlerCfgDefn.getInstance(); 311 ClassPropertyDefinition propertyDefinition = 312 definition.getJavaClassPropertyDefinition(); 313 Class<? extends AlertHandler> handlerClass = 314 propertyDefinition.loadClass(className, AlertHandler.class); 315 AlertHandler handler = handlerClass.newInstance(); 316 317 if (initialize) 318 { 319 handler.initializeAlertHandler(configuration); 320 } 321 else 322 { 323 List<LocalizableMessage> unacceptableReasons = new ArrayList<>(); 324 if (!handler.isConfigurationAcceptable(configuration, unacceptableReasons)) 325 { 326 String reasons = Utils.joinAsString(". ", unacceptableReasons); 327 throw new InitializationException( 328 ERR_CONFIG_ALERTHANDLER_CONFIG_NOT_ACCEPTABLE.get(configuration.dn(), reasons)); 329 } 330 } 331 332 return handler; 333 } 334 catch (Exception e) 335 { 336 LocalizableMessage message = ERR_CONFIG_ALERTHANDLER_INITIALIZATION_FAILED. 337 get(className, configuration.dn(), stackTraceToSingleLineString(e)); 338 throw new InitializationException(message, e); 339 } 340 } 341}