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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.server.core; 028 029import static org.opends.messages.ConfigMessages.*; 030import static org.opends.server.util.StaticUtils.*; 031 032import java.util.List; 033import java.util.concurrent.ConcurrentHashMap; 034 035import org.forgerock.i18n.LocalizableMessage; 036import org.forgerock.i18n.slf4j.LocalizedLogger; 037import org.forgerock.opendj.config.server.ConfigException; 038import org.forgerock.opendj.ldap.ResultCode; 039import org.opends.server.admin.ClassPropertyDefinition; 040import org.opends.server.admin.server.ConfigurationAddListener; 041import org.opends.server.admin.server.ConfigurationChangeListener; 042import org.opends.server.admin.server.ConfigurationDeleteListener; 043import org.opends.server.admin.server.ServerManagementContext; 044import org.opends.server.admin.std.meta.MonitorProviderCfgDefn; 045import org.opends.server.admin.std.server.MonitorProviderCfg; 046import org.opends.server.admin.std.server.RootCfg; 047import org.opends.server.api.MonitorProvider; 048import org.forgerock.opendj.config.server.ConfigChangeResult; 049import org.opends.server.types.DN; 050import org.opends.server.types.InitializationException; 051 052/** 053 * This class defines a utility that will be used to manage the set of monitor 054 * providers defined in the Directory Server. It will initialize the monitor 055 * providers when the server starts, and then will manage any additions, 056 * removals, or modifications to any providers while the server is running. 057 */ 058public class MonitorConfigManager 059 implements ConfigurationChangeListener<MonitorProviderCfg>, 060 ConfigurationAddListener<MonitorProviderCfg>, 061 ConfigurationDeleteListener<MonitorProviderCfg> 062 063{ 064 065 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 066 067 /** 068 * A mapping between the DNs of the config entries and the associated monitor 069 * providers. 070 */ 071 private final ConcurrentHashMap<DN,MonitorProvider<?>> monitors; 072 073 private final ServerContext serverContext; 074 075 /** 076 * Creates a new instance of this monitor provider config manager. 077 * 078 * @param serverContext 079 * The server context. 080 */ 081 public MonitorConfigManager(ServerContext serverContext) 082 { 083 this.serverContext = serverContext; 084 monitors = new ConcurrentHashMap<>(); 085 } 086 087 /** 088 * Initializes all monitor providers currently defined in the Directory Server 089 * configuration. This should only be called at Directory Server startup. 090 * 091 * @throws ConfigException If a configuration problem causes the monitor 092 * provider initialization process to fail. 093 * 094 * @throws InitializationException If a problem occurs while initializing 095 * the monitor providers that is not related 096 * to the server configuration. 097 */ 098 public void initializeMonitorProviders() 099 throws ConfigException, InitializationException 100 { 101 // Get the root configuration object. 102 ServerManagementContext managementContext = 103 ServerManagementContext.getInstance(); 104 RootCfg rootConfiguration = 105 managementContext.getRootConfiguration(); 106 107 108 // Register as an add and delete listener with the root configuration so we 109 // can be notified if any monitor provider entries are added or removed. 110 rootConfiguration.addMonitorProviderAddListener(this); 111 rootConfiguration.addMonitorProviderDeleteListener(this); 112 113 114 //Initialize the existing monitor providers. 115 for (String name : rootConfiguration.listMonitorProviders()) 116 { 117 MonitorProviderCfg monitorConfig = 118 rootConfiguration.getMonitorProvider(name); 119 monitorConfig.addChangeListener(this); 120 121 if (monitorConfig.isEnabled()) 122 { 123 String className = monitorConfig.getJavaClass(); 124 try 125 { 126 MonitorProvider<? extends MonitorProviderCfg> monitor = 127 loadMonitor(className, monitorConfig); 128 monitors.put(monitorConfig.dn(), monitor); 129 DirectoryServer.registerMonitorProvider(monitor); 130 } 131 catch (InitializationException ie) 132 { 133 logger.error(ie.getMessageObject()); 134 continue; 135 } 136 } 137 } 138 } 139 140 141 142 /** {@inheritDoc} */ 143 @Override 144 public boolean isConfigurationAddAcceptable( 145 MonitorProviderCfg configuration, 146 List<LocalizableMessage> unacceptableReasons) 147 { 148 if (configuration.isEnabled()) 149 { 150 // Get the name of the class and make sure we can instantiate it as a 151 // monitor provider. 152 String className = configuration.getJavaClass(); 153 try 154 { 155 loadMonitor(className, null); 156 } 157 catch (InitializationException ie) 158 { 159 unacceptableReasons.add(ie.getMessageObject()); 160 return false; 161 } 162 } 163 164 // If we've gotten here, then it's fine. 165 return true; 166 } 167 168 169 170 /** {@inheritDoc} */ 171 @Override 172 public ConfigChangeResult applyConfigurationAdd( 173 MonitorProviderCfg configuration) 174 { 175 final ConfigChangeResult ccr = new ConfigChangeResult(); 176 177 configuration.addChangeListener(this); 178 179 if (! configuration.isEnabled()) 180 { 181 return ccr; 182 } 183 184 MonitorProvider<? extends MonitorProviderCfg> monitor = null; 185 186 // Get the name of the class and make sure we can instantiate it as a 187 // monitor provider. 188 String className = configuration.getJavaClass(); 189 try 190 { 191 monitor = loadMonitor(className, configuration); 192 } 193 catch (InitializationException ie) 194 { 195 ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode()); 196 ccr.addMessage(ie.getMessageObject()); 197 } 198 199 if (ccr.getResultCode() == ResultCode.SUCCESS) 200 { 201 monitors.put(configuration.dn(), monitor); 202 DirectoryServer.registerMonitorProvider(monitor); 203 } 204 205 return ccr; 206 } 207 208 209 210 /** {@inheritDoc} */ 211 @Override 212 public boolean isConfigurationDeleteAcceptable( 213 MonitorProviderCfg configuration, 214 List<LocalizableMessage> unacceptableReasons) 215 { 216 // It will always be acceptable to delete or disable a monitor provider. 217 return true; 218 } 219 220 221 222 /** {@inheritDoc} */ 223 @Override 224 public ConfigChangeResult applyConfigurationDelete( 225 MonitorProviderCfg configuration) 226 { 227 final ConfigChangeResult ccr = new ConfigChangeResult(); 228 229 MonitorProvider<?> monitor = monitors.remove(configuration.dn()); 230 if (monitor != null) 231 { 232 DirectoryServer.deregisterMonitorProvider(monitor); 233 monitor.finalizeMonitorProvider(); 234 } 235 236 return ccr; 237 } 238 239 240 241 /** {@inheritDoc} */ 242 @Override 243 public boolean isConfigurationChangeAcceptable( 244 MonitorProviderCfg configuration, 245 List<LocalizableMessage> unacceptableReasons) 246 { 247 if (configuration.isEnabled()) 248 { 249 // Get the name of the class and make sure we can instantiate it as a 250 // monitor provider. 251 String className = configuration.getJavaClass(); 252 try 253 { 254 loadMonitor(className, null); 255 } 256 catch (InitializationException ie) 257 { 258 unacceptableReasons.add(ie.getMessageObject()); 259 return false; 260 } 261 } 262 263 // If we've gotten here, then it's fine. 264 return true; 265 } 266 267 268 269 /** {@inheritDoc} */ 270 @Override 271 public ConfigChangeResult applyConfigurationChange( 272 MonitorProviderCfg configuration) 273 { 274 final ConfigChangeResult ccr = new ConfigChangeResult(); 275 276 // Get the existing monitor provider if it's already enabled. 277 MonitorProvider<?> existingMonitor = monitors.get(configuration.dn()); 278 279 // If the new configuration has the monitor disabled, then disable it if it 280 // is enabled, or do nothing if it's already disabled. 281 if (! configuration.isEnabled()) 282 { 283 if (existingMonitor != null) 284 { 285 DirectoryServer.deregisterMonitorProvider(existingMonitor); 286 MonitorProvider<?> monitor = monitors.remove(configuration.dn()); 287 if (monitor != null) 288 { 289 monitor.finalizeMonitorProvider(); 290 } 291 } 292 293 return ccr; 294 } 295 296 297 // Get the class for the monitor provider. If the monitor is already 298 // enabled, then we shouldn't do anything with it although if the class has 299 // changed then we'll at least need to indicate that administrative action 300 // is required. If the monitor is disabled, then instantiate the class and 301 // initialize and register it as a monitor provider. 302 String className = configuration.getJavaClass(); 303 if (existingMonitor != null) 304 { 305 if (! className.equals(existingMonitor.getClass().getName())) 306 { 307 ccr.setAdminActionRequired(true); 308 } 309 310 return ccr; 311 } 312 313 MonitorProvider<? extends MonitorProviderCfg> monitor = null; 314 try 315 { 316 monitor = loadMonitor(className, configuration); 317 } 318 catch (InitializationException ie) 319 { 320 ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode()); 321 ccr.addMessage(ie.getMessageObject()); 322 } 323 324 if (ccr.getResultCode() == ResultCode.SUCCESS) 325 { 326 monitors.put(configuration.dn(), monitor); 327 DirectoryServer.registerMonitorProvider(monitor); 328 } 329 330 return ccr; 331 } 332 333 334 335 /** 336 * Loads the specified class, instantiates it as a monitor provider, and 337 * optionally initializes that instance. 338 * 339 * @param className The fully-qualified name of the monitor provider 340 * class to load, instantiate, and initialize. 341 * @param configuration The configuration to use to initialize the monitor 342 * provider, or {@code null} if the monitor provider 343 * should not be initialized. 344 * 345 * @return The possibly initialized monitor provider. 346 * 347 * @throws InitializationException If a problem occurred while attempting to 348 * initialize the monitor provider. 349 */ 350 private <T extends MonitorProviderCfg> MonitorProvider<T> 351 loadMonitor(String className, T configuration) 352 throws InitializationException 353 { 354 try 355 { 356 MonitorProviderCfgDefn definition = MonitorProviderCfgDefn.getInstance(); 357 ClassPropertyDefinition propertyDefinition = 358 definition.getJavaClassPropertyDefinition(); 359 @SuppressWarnings("unchecked") 360 Class<? extends MonitorProvider<T>> providerClass = 361 (Class<? extends MonitorProvider<T>>) propertyDefinition 362 .loadClass(className, MonitorProvider.class); 363 MonitorProvider<T> monitor = providerClass.newInstance(); 364 365 if (configuration != null) 366 { 367 monitor.initializeMonitorProvider(configuration); 368 } 369 370 return monitor; 371 } 372 catch (Exception e) 373 { 374 LocalizableMessage message = ERR_CONFIG_MONITOR_INITIALIZATION_FAILED. 375 get(className, configuration.dn(), stackTraceToSingleLineString(e)); 376 throw new InitializationException(message, e); 377 } 378 } 379} 380