/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.core; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.opends.server.api.EntryCache; import org.opends.server.extensions.DefaultEntryCache; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.ErrorLogCategory; import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.InitializationException; import org.opends.server.types.ResultCode; import org.opends.server.config.ConfigException; import org.opends.server.types.DebugLogLevel; import static org.opends.server.loggers.ErrorLogger.*; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import static org.opends.server.messages.ConfigMessages.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.util.StaticUtils.*; import org.opends.server.admin.ClassPropertyDefinition; import org.opends.server.admin.server.ConfigurationAddListener; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.server.ConfigurationDeleteListener; import org.opends.server.admin.server.ServerManagementContext; import org.opends.server.admin.std.server.EntryCacheCfg; import org.opends.server.admin.std.server.RootCfg; import org.opends.server.admin.std.meta.EntryCacheCfgDefn; /** * This class defines a utility that will be used to manage the configuration * for the Directory Server entry cache. Only a single entry cache may be * defined, but if it is absent or disabled, then a default cache will be used. */ public class EntryCacheConfigManager implements ConfigurationChangeListener , ConfigurationAddListener , ConfigurationDeleteListener { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // The current entry cache registered in the server private EntryCache _entryCache = null; // The default entry cache to use when no entry cache has been configured // or when the configured entry cache could not be initialized. private EntryCache _defaultEntryCache = null; /** * Creates a new instance of this entry cache config manager. */ public EntryCacheConfigManager() { // No implementation is required. } /** * Initializes the default entry cache. * This should only be called at Directory Server startup. * * @throws InitializationException If a problem occurs while trying to * install the default entry cache. */ public void initializeDefaultEntryCache() throws InitializationException { try { DefaultEntryCache defaultCache = new DefaultEntryCache(); defaultCache.initializeEntryCache(null); DirectoryServer.setEntryCache(defaultCache); _defaultEntryCache = defaultCache; } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } int msgID = MSGID_CONFIG_ENTRYCACHE_CANNOT_INSTALL_DEFAULT_CACHE; String message = getMessage(msgID, stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } } /** * Initializes the configuration associated with the Directory Server entry * cache. This should only be called at Directory Server startup. If an * error occurs, then a message will be logged and the default entry cache * will be installed. * * @throws ConfigException If a configuration problem causes the entry * cache initialization process to fail. */ public void initializeEntryCache() throws ConfigException { // Get the root configuration object. ServerManagementContext managementContext = ServerManagementContext.getInstance(); RootCfg rootConfiguration = managementContext.getRootConfiguration(); // Default entry cache should be already installed with // initializeDefaultEntryCache() method so // that there will be one even if we encounter a problem // later. // Register as an add and delete listener with the root configuration so we // can be notified if any entry cache entry is added or removed. // If entry cache configuration is using a one-to-zero-or-one relation // then uncomment the lines below (see issue #1558). /* // rootConfiguration.addEntryCacheAddListener(this); // rootConfiguration.addEntryCacheDeleteListener(this); */ // If the entry cache configuration is not present then keep the // default entry cache already installed. // If entry cache configuration is using a one-to-zero-or-one relation // then uncomment the lines below (see issue #1558). /* // if (!rootConfiguration.hasEntryCache()) // { // logError( // ErrorLogCategory.CONFIGURATION, // ErrorLogSeverity.SEVERE_WARNING, // MSGID_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY // ); // return; // } */ // Get the entry cache configuration. EntryCacheCfg configuration = rootConfiguration.getEntryCache(); // At this point, we have a configuration entry. Register a change // listener with it so we can be notified of changes to it over time. configuration.addChangeListener(this); // Initialize the entry cache. if (configuration.isEnabled()) { // Load the entry cache implementation class and install the entry // cache with the server. String className = configuration.getEntryCacheClass(); try { loadAndInstallEntryCache (className, configuration); } catch (InitializationException ie) { logError( ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR, ie.getMessage(), ie.getMessageID()); } } } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable( EntryCacheCfg configuration, List unacceptableReasons ) { // returned status -- all is fine by default boolean status = true; if (configuration.isEnabled()) { // Get the name of the class and make sure we can instantiate it as an // entry cache. String className = configuration.getEntryCacheClass(); try { // Load the class but don't initialize it. loadEntryCache(className, null); } catch (InitializationException ie) { unacceptableReasons.add(ie.getMessage()); status = false; } } return status; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange( EntryCacheCfg configuration ) { // Returned result. ConfigChangeResult changeResult = new ConfigChangeResult( ResultCode.SUCCESS, false, new ArrayList() ); // If the new configuration has the entry cache disabled, then install // the default entry cache with the server. if (! configuration.isEnabled()) { DirectoryServer.setEntryCache (_defaultEntryCache); // If an entry cache was installed then clean it. if (_entryCache != null) { _entryCache.finalizeEntryCache(); _entryCache = null; } return changeResult; } // At this point, new configuration is enabled... // If the current entry cache is already enabled then we don't do // anything unless the class has changed in which case we should // indicate that administrative action is required. String newClassName = configuration.getEntryCacheClass(); if (_entryCache !=null) { String curClassName = _entryCache.getClass().getName(); boolean classIsNew = (! newClassName.equals (curClassName)); if (classIsNew) { changeResult.setAdminActionRequired (true); } return changeResult; } // New entry cache is enabled and there were no previous one. // Instantiate the new class and initalize it. try { loadAndInstallEntryCache (newClassName, configuration); } catch (InitializationException ie) { changeResult.addMessage (ie.getMessage()); changeResult.setResultCode (DirectoryServer.getServerErrorResultCode()); return changeResult; } return changeResult; } /** * {@inheritDoc} */ public boolean isConfigurationAddAcceptable( EntryCacheCfg configuration, List unacceptableReasons ) { // returned status -- all is fine by default boolean status = true; if (configuration.isEnabled()) { // Get the name of the class and make sure we can instantiate it as // an entry cache. String className = configuration.getEntryCacheClass(); try { // Load the class but don't initialize it. loadEntryCache(className, null); } catch (InitializationException ie) { unacceptableReasons.add (ie.getMessage()); status = false; } } return status; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationAdd( EntryCacheCfg configuration ) { // Returned result. ConfigChangeResult changeResult = new ConfigChangeResult( ResultCode.SUCCESS, false, new ArrayList() ); // Register a change listener with it so we can be notified of changes // to it over time. configuration.addChangeListener(this); if (configuration.isEnabled()) { // Instantiate the class as an entry cache and initialize it. String className = configuration.getEntryCacheClass(); try { loadAndInstallEntryCache (className, configuration); } catch (InitializationException ie) { changeResult.addMessage (ie.getMessage()); changeResult.setResultCode (DirectoryServer.getServerErrorResultCode()); return changeResult; } } return changeResult; } /** * {@inheritDoc} */ public boolean isConfigurationDeleteAcceptable( EntryCacheCfg configuration, List unacceptableReasons ) { // NYI // If we've gotten to this point, then it is acceptable as far as we are // concerned. If it is unacceptable according to the configuration, then // the entry cache itself will make that determination. return true; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete( EntryCacheCfg configuration ) { // Returned result. ConfigChangeResult changeResult = new ConfigChangeResult( ResultCode.SUCCESS, false, new ArrayList() ); // If the entry cache was installed then replace it with the // default entry cache, and clean it. if (_entryCache != null) { DirectoryServer.setEntryCache (_defaultEntryCache); _entryCache.finalizeEntryCache(); _entryCache = null; } return changeResult; } /** * Loads the specified class, instantiates it as an entry cache, * and optionally initializes that instance. Any initialize entry * cache is registered in the server. * * @param className The fully-qualified name of the entry cache * class to load, instantiate, and initialize. * @param configuration The configuration to use to initialize the * entry cache, or {@code null} if the * entry cache should not be initialized. * * @throws InitializationException If a problem occurred while attempting * to initialize the entry cache. */ private void loadAndInstallEntryCache( String className, EntryCacheCfg configuration ) throws InitializationException { // Load the entry cache class... EntryCache entryCache = loadEntryCache (className, configuration); // ... and install the entry cache in the server. DirectoryServer.setEntryCache(entryCache); _entryCache = entryCache; } /** * Loads the specified class, instantiates it as an entry cache, * and optionally initializes that instance. * * @param className The fully-qualified name of the entry cache * class to load, instantiate, and initialize. * @param configuration The configuration to use to initialize the * entry cache, or {@code null} if the * entry cache should not be initialized. * * @return The possibly initialized entry cache. * * @throws InitializationException If a problem occurred while attempting * to initialize the entry cache. */ private EntryCache loadEntryCache( String className, EntryCacheCfg configuration ) throws InitializationException { try { EntryCacheCfgDefn definition; ClassPropertyDefinition propertyDefinition; Class cacheClass; EntryCache cache; definition = EntryCacheCfgDefn.getInstance(); propertyDefinition = definition.getEntryCacheClassPropertyDefinition(); cacheClass = propertyDefinition.loadClass(className, EntryCache.class); cache = (EntryCache) cacheClass.newInstance(); if (configuration != null) { Method method = cache.getClass().getMethod( "initializeEntryCache", configuration.definition().getServerConfigurationClass() ); method.invoke(cache, configuration); } return cache; } catch (Exception e) { int msgID = MSGID_CONFIG_ENTRYCACHE_CANNOT_INITIALIZE_CACHE; String message = getMessage( msgID, className, String.valueOf(configuration.dn()), stackTraceToSingleLineString(e) ); throw new InitializationException(msgID, message, e); } } }