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