mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

abobrov
02.05.2007 1649148841be6bc4ac6381d0592dc9ab52438044
- [Issue 1481] Ability to set any JE property in config.ldif
- [Issue 2031] provide core JE configurable attributes for FileSystemEntryCache
- fixes to entry cache config manager for proper configuration, re-configuration, error reporting.
13 files modified
829 ■■■■ changed files
opends/resource/schema/02-config.ldif 8 ●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/FileSystemEntryCacheConfiguration.xml 35 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml 30 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml 2 ●●● patch | view | raw | blame | history
opends/src/messages/messages/config.properties 15 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/extension.properties 29 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/ConfigurableEnvironment.java 101 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/RootContainer.java 46 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/EntryCacheConfigManager.java 116 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/EntryCacheCommon.java 70 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/FIFOEntryCache.java 40 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java 294 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java 43 ●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif
@@ -1519,6 +1519,9 @@
  NAME 'ds-task-import-clear-backend'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.452
  NAME 'ds-cfg-je-property' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.453
  NAME 'ds-task-disconnect-connection-id'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE
@@ -1662,7 +1665,7 @@
  ds-cfg-database-checkpointer-bytes-interval $
  ds-cfg-database-checkpointer-wakeup-interval $
  ds-cfg-database-lock-num-lock-tables $ ds-cfg-database-cleaner-num-threads $
  ds-cfg-backend-compact-encoding )
  ds-cfg-backend-compact-encoding $ ds-cfg-je-property )
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.7 NAME 'ds-cfg-je-database'
  SUP top STRUCTURAL MAY ( cn $ ds-cfg-database-cache-percent $
@@ -2180,7 +2183,8 @@
  ds-cfg-max-memory-size $ ds-cfg-lock-timeout $ ds-cfg-exclude-filter $
  ds-cfg-include-filter $ ds-cfg-cache-directory $ ds-cfg-cache-type $
  ds-cfg-persistent-cache $ ds-cfg-backend-compact-encoding $
  ds-cfg-database-cache-percent $ ds-cfg-database-cache-size )
  ds-cfg-database-cache-percent $ ds-cfg-database-cache-size $
  ds-cfg-je-property )
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.114 NAME 'ds-cfg-plugin-root'
  SUP top AUXILIARY MAY ( ds-cfg-plugin-order-startup $
opends/src/admin/defn/org/opends/server/admin/std/FileSystemEntryCacheConfiguration.xml
@@ -290,6 +290,41 @@
    </adm:profile>
  </adm:property>
  <adm:property name="je-property"
    multi-valued="true">
    <adm:synopsis>
      Specifies the environment properties for the Berkeley DB Java
      Edition database providing the backend for this entry cache.
    </adm:synopsis>
    <adm:description>
      Any Berkeley DB Java Edition property can be specified using the
      following form: property-name=property-value
      Refer to OpenDS documentation for further information on related
      properties, their implications and range values. The definitive
      identification of all the property parameters available in the
      example.properties file of Berkeley DB Java Edition distribution.
    </adm:description>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>je.log.fileMax=10485760</adm:value>
        <adm:value>je.cleaner.minUtilization=90</adm:value>
        <adm:value>je.cleaner.maxBatchFiles=1</adm:value>
        <adm:value>je.cleaner.minAge=1</adm:value>
        <adm:value>je.cleaner.minFileUtilization=50</adm:value>
        <adm:value>je.checkpointer.bytesInterval=10485760</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.452</ldap:oid>
        <ldap:name>ds-cfg-je-property</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property-reference name="include-filter"/>
  <adm:property-reference name="exclude-filter"/>
opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml
@@ -991,4 +991,32 @@
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
  <adm:property name="je-property"
    mandatory="false"
    multi-valued="true">
    <adm:synopsis>
      Specifies the database and environment properties for the Berkeley DB
      Java Edition database serving the data for this backend.
    </adm:synopsis>
    <adm:description>
      Any Berkeley DB Java Edition property can be specified using the
      following form: property-name=property-value
      Refer to OpenDS documentation for further information on related
      properties, their implications and range values. The definitive
      identification of all the property parameters available in the
      example.properties file of Berkeley DB Java Edition distribution.
    </adm:description>
    <adm:default-behavior>
      <adm:undefined />
    </adm:default-behavior>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.452</ldap:oid>
        <ldap:name>ds-cfg-je-property</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -206,7 +206,7 @@
    </adm:profile>
  </adm:relation>
  <adm:relation name="entry-cache">
    <adm:one-to-one />
    <adm:one-to-zero-or-one />
    <adm:profile name="ldap">
      <ldap:rdn-sequence>cn=Entry Cache,cn=config</ldap:rdn-sequence>
    </adm:profile>
opends/src/messages/messages/config.properties
@@ -698,7 +698,7 @@
SEVERE_ERR_CONFIG_ENTRYCACHE_CANNOT_GET_CONFIG_ENTRY_201=An unexpected error \
 occurred while attempting to get the "cn=Entry Cache,cn=config" entry, which \
 holds the entry cache configuration:  %s.  No entry cache will be available
SEVERE_ERR_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY_202=The entry cache \
SEVERE_WARN_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY_202=The entry cache \
 configuration entry "cn=Entry Cache,cn=config" does not exist in the \
 Directory Server configuration.  No entry cache will be available until this \
 entry is created with a valid entry cache configuration
@@ -2148,3 +2148,16 @@
SEVERE_WARN_CONFIG_FILE_NO_STARTOK_FILE_703=No last known good configuration \
 file %s exists.  The server will attempt to start using the active \
 configuration file %s
SEVERE_ERR_CONFIG_JE_PROPERTY_INVALID_704=An error occurred while \
 trying to parse and validate Berkeley DB JE property %s:  %s
SEVERE_ERR_CONFIG_JE_PROPERTY_INVALID_FORM_705=An error occurred while \
 trying to parse and validate Berkeley DB JE property %s: the property \
 does not follow a singular property=value form
SEVERE_ERR_CONFIG_JE_PROPERTY_SHADOWS_CONFIG_706=An error occurred while \
 trying to parse and validate Berkeley DB JE property %s: the property \
 shadows configuration attribute %s
SEVERE_ERR_CONFIG_JE_DUPLICATE_PROPERTY_707=An error occurred while \
 trying to parse and validate Berkeley DB JE property %s: the property \
 is already defined for this component
INFO_CONFIG_JE_PROPERTY_REQUIRES_RESTART_708=Setting Berkeley DB JE property \
 %s will not take effect until the component for which it is set is restarted
opends/src/messages/messages/extension.properties
@@ -124,10 +124,8 @@
 while attempting to determine the value of the ds-cfg-exclude-filter \
 attribute in configuration entry %s:  %s.  All entries will be considered \
 eligible for inclusion in the cache
SEVERE_ERR_FIFOCACHE_INVALID_MAX_MEMORY_PCT_20=The ds-cfg-max-memory-percent \
 attribute of entry %s, which holds the maximum percentage of JVM memory \
 available for use in the entry cache, has an invalid value:  %s.  Its value \
 must be an integer between 1 and 100
FATAL_ERR_FIFOCACHE_CANNOT_INITIALIZE_20=A fatal error occurred while trying \
 to initialize fifo entry cache:  %s
SEVERE_ERR_FIFOCACHE_INVALID_MAX_ENTRIES_21=The ds-cfg-max-entries attribute \
 of entry %s, which specifies the maximum number of entries that may be held \
 in the entry cache, has an invalid value:  %s.  Its value must be a positive \
@@ -973,9 +971,8 @@
 of time in milliseconds that the entry cache should block while attempting to \
 acquire a lock for an entry.  Changes to this configuration attribute will \
 take effect immediately
SEVERE_ERR_SOFTREFCACHE_CANNOT_DETERMINE_LOCK_TIMEOUT_279=An error occurred \
 while attempting to determine the value of the ds-cfg-lock-timeout attribute \
 in configuration entry %s:  %s.  The default of %d will be used
FATAL_ERR_SOFTREFCACHE_CANNOT_INITIALIZE_279=A fatal error occurred while \
 trying to initialize soft reference entry cache:  %s
INFO_SOFTREFCACHE_DESCRIPTION_INCLUDE_FILTERS_280=Specifies a set of search \
 filters that may be used to indicate which entries should be included in the \
 entry cache.  Entries that do not match at least one of these filters will \
@@ -1581,7 +1578,7 @@
SEVERE_ERR_FSCACHE_CANNOT_STORE_PERSISTENT_DATA_487=An error occurred while \
 trying to store persistent cache. Persistent cache will be flushed now
FATAL_ERR_FSCACHE_CANNOT_INITIALIZE_488=A fatal error occurred while trying \
 to initialize file system entry cache. This cache will be disabled now
 to initialize file system entry cache:  %s
SEVERE_ERR_FSCACHE_CANNOT_STORE_ENTRY_489=Unable to store new cache entry in \
 the file system entry cache
SEVERE_ERR_FSCACHE_CANNOT_RETRIEVE_ENTRY_490=Unable to retrieve an existing \
@@ -1592,21 +1589,23 @@
SEVERE_ERR_FSCACHE_CANNOT_SET_JE_MEMORY_SIZE_492=Internal error occurred \
 while trying to set the entry cache backend internal cache size in bytes. The \
 previous or default value will be used instead
FATAL_ERR_FSCACHE_HOMELESS_493=A fatal error occurred while trying to setup \
SEVERE_ERR_FSCACHE_CANNOT_SET_JE_PROPERTIES_493=Internal error occurred \
 while trying to set the entry cache backend Berkeley DB JE properties:  %s
FATAL_ERR_FSCACHE_HOMELESS_494=A fatal error occurred while trying to setup \
 file system entry cache home. No suitable path can be found to host the cache \
 home
SEVERE_WARN_FSCACHE_SET_PERMISSIONS_FAILED_494=Unable to set file permissions \
SEVERE_WARN_FSCACHE_SET_PERMISSIONS_FAILED_495=Unable to set file permissions \
 for the file system entry cache backend database directory %s
SEVERE_WARN_FSCACHE_OFFLINE_STATE_FAIL_495=%s backend current offline state \
SEVERE_WARN_FSCACHE_OFFLINE_STATE_FAIL_496=%s backend current offline state \
 does not match persistent cache last recorded offline state. All cached data \
 for this backend is now discarded
NOTICE_FSCACHE_RESTORE_PROGRESS_REPORT_496=Restored %d cache entries of %d \
NOTICE_FSCACHE_RESTORE_PROGRESS_REPORT_497=Restored %d cache entries of %d \
 total persistent cache entries found
NOTICE_FSCACHE_SAVE_PROGRESS_REPORT_497=Made persistent %d cache entries of %d \
NOTICE_FSCACHE_SAVE_PROGRESS_REPORT_498=Made persistent %d cache entries of %d \
 total cache entries found
NOTICE_FSCACHE_INDEX_NOT_FOUND_498=No previous persistent cache state can be \
NOTICE_FSCACHE_INDEX_NOT_FOUND_499=No previous persistent cache state can be \
 found. Starting with an empty cache
SEVERE_ERR_FSCACHE_INDEX_IMPAIRED_499=The persistent cache index is \
SEVERE_ERR_FSCACHE_INDEX_IMPAIRED_500=The persistent cache index is \
 inconsistent or damaged. Persistent cache will be flushed now
MILD_ERR_ENTRYUUID_VATTR_NOT_SEARCHABLE_501=The %s attribute is not \
 searchable and should not be included in otherwise unindexed search filters
opends/src/server/org/opends/server/backends/jeb/ConfigurableEnvironment.java
@@ -35,8 +35,11 @@
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.SortedSet;
import java.util.StringTokenizer;
import org.opends.messages.Message;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.admin.std.server.JEBackendCfg;
import org.opends.server.admin.std.meta.JEBackendCfgDefn;
@@ -44,6 +47,9 @@
import org.opends.server.admin.BooleanPropertyDefinition;
import org.opends.server.admin.PropertyDefinition;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.ConfigMessages.*;
/**
 * This class maps JE properties to configuration attributes.
 */
@@ -166,6 +172,13 @@
  /**
   * The name of the attribute which may specify any native JE properties.
   */
  public static final String ATTR_JE_PROPERTY =
       ConfigConstants.NAME_PREFIX_CFG + "je-property";
  /**
   * A map of JE property names to the corresponding configuration attribute.
   */
  private static HashMap<String, String> attrMap =
@@ -391,6 +404,92 @@
      envConfig.setConfigParam(jeProperty, value);
    }
    // See if there are any native JE properties specified in the config
    // and if so try to parse, evaluate and set them.
    SortedSet<String> jeProperties = cfg.getJEProperty();
    try {
      envConfig = setJEProperties(envConfig, jeProperties, attrMap);
    } catch (ConfigException e) {
      throw e;
    }
    return envConfig;
  }
  /**
   * Parse, validate and set native JE environment properties for
   * a given environment config.
   *
   * @param  envConfig The JE environment config for which to set
   *                   the properties.
   * @param  jeProperties The JE environment properties to parse,
   *                      validate and set.
   * @param  configAttrMap Component supported JE properties to
   *                       their configuration attributes map.
   * @return An environment config instance with given properties
   *         set.
   * @throws ConfigException If there is an error while parsing,
   *         validating and setting any of the properties provided.
   */
  public static EnvironmentConfig setJEProperties(EnvironmentConfig envConfig,
    SortedSet<String> jeProperties, HashMap<String, String> configAttrMap)
    throws ConfigException
  {
    if (jeProperties.isEmpty()) {
      // return default config.
      return envConfig;
    }
    // Set to catch duplicate properties.
    HashSet<String> uniqueJEProperties = new HashSet<String>();
    // Iterate through the config values associated with a JE property.
    for (String jeEntry : jeProperties)
    {
      StringTokenizer st = new StringTokenizer(jeEntry, "=");
      if (st.countTokens() == 2) {
        String jePropertyName = st.nextToken();
        String jePropertyValue = st.nextToken();
        // Check if it is a duplicate.
        if (uniqueJEProperties.contains(jePropertyName)) {
          Message message = ERR_CONFIG_JE_DUPLICATE_PROPERTY.get(
              jePropertyName);
            throw new ConfigException(message);
        }
        // Set JE property.
        try {
          envConfig.setConfigParam(jePropertyName, jePropertyValue);
          // This is a special case that JE cannot validate before
          // actually setting it. Validate it before it gets to JE.
          if (jePropertyName.equals("java.util.logging.level")) {
            java.util.logging.Level.parse(jePropertyValue);
          }
          // If this property shadows an existing config attribute.
          if (configAttrMap.containsKey(jePropertyName)) {
            Message message = ERR_CONFIG_JE_PROPERTY_SHADOWS_CONFIG.get(
              jePropertyName, attrMap.get(jePropertyName));
            throw new ConfigException(message);
          }
          // Add this property to unique set.
          uniqueJEProperties.add(jePropertyName);
        } catch(IllegalArgumentException e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          Message message =
            ERR_CONFIG_JE_PROPERTY_INVALID.get(
            jeEntry, e.getMessage());
          throw new ConfigException(message, e.getCause());
        }
      } else {
        Message message =
          ERR_CONFIG_JE_PROPERTY_INVALID_FORM.get(jeEntry);
        throw new ConfigException(message);
      }
    }
    return envConfig;
  }
opends/src/server/org/opends/server/backends/jeb/RootContainer.java
@@ -43,6 +43,12 @@
import org.opends.server.types.FilePermission;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.ResultCode;
import org.opends.server.api.Backend;
import org.opends.server.admin.std.server.JEBackendCfg;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.core.DirectoryServer;
import org.opends.server.config.ConfigException;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
@@ -51,14 +57,8 @@
    ERR_CONFIG_BACKEND_MODE_INVALID;
import static org.opends.messages.ConfigMessages.
    WARN_CONFIG_BACKEND_INSANE_MODE;
import org.opends.server.api.Backend;
import org.opends.server.admin.std.server.JEBackendCfg;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.core.DirectoryServer;
import org.opends.server.config.ConfigException;
import static org.opends.server.util.StaticUtils.getFileForPath;
import org.opends.server.util.StaticUtils;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.messages.ConfigMessages.*;
/**
 * Wrapper class for the JE environment. Root container holds all the entry
@@ -780,6 +780,34 @@
        EnvironmentConfig newEnvConfig =
            ConfigurableEnvironment.parseConfigEntry(cfg);
        Map paramsMap = EnvironmentParams.SUPPORTED_PARAMS;
        // Iterate through native JE properties.
        SortedSet<String> jeProperties = cfg.getJEProperty();
        for (String jeEntry : jeProperties) {
          // There is no need to validate properties yet again.
          StringTokenizer st = new StringTokenizer(jeEntry, "=");
          if (st.countTokens() == 2) {
            String jePropertyName = st.nextToken();
            String jePropertyValue = st.nextToken();
            ConfigParam param = (ConfigParam) paramsMap.get(jePropertyName);
            if (!param.isMutable()) {
              String oldValue = oldEnvConfig.getConfigParam(param.getName());
              String newValue = jePropertyValue;
              if (!oldValue.equalsIgnoreCase(newValue)) {
                adminActionRequired = true;
                messages.add(INFO_CONFIG_JE_PROPERTY_REQUIRES_RESTART.get(
                        jePropertyName));
                if(debugEnabled()) {
                  TRACER.debugInfo("The change to the following property " +
                    "will take effect when the component is restarted: " +
                    jePropertyName);
                }
              }
            }
          }
        }
        // Iterate through JE configuration attributes.
        for (Object o : paramsMap.values())
        {
          ConfigParam param = (ConfigParam) o;
@@ -820,7 +848,7 @@
    }
    catch (Exception e)
    {
      messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(e)));
      messages.add(Message.raw(stackTraceToSingleLineString(e)));
      ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
                                   adminActionRequired,
                                   messages);
opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
@@ -50,18 +50,15 @@
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
import org.opends.messages.MessageBuilder;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.messages.ConfigMessages.*;
import org.opends.messages.MessageBuilder;
import static org.opends.server.util.StaticUtils.*;
/**
 * 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
@@ -152,28 +149,16 @@
    // 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);
    */
    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,
    //          ERR_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY
    //          );
    //      return;
    //    }
    */
    if (!rootConfiguration.hasEntryCache())
    {
      logError(WARN_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY.get());
      return;
    }
    // Get the entry cache configuration.
    EntryCacheCfg configuration = rootConfiguration.getEntryCache();
@@ -190,7 +175,7 @@
      String className = configuration.getEntryCacheClass();
      try
      {
        loadAndInstallEntryCache (className, configuration);
        loadAndInstallEntryCache (className);
      }
      catch (InitializationException ie)
      {
@@ -211,21 +196,15 @@
    // 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, configuration, false);
      }
      catch (InitializationException ie)
      {
        unacceptableReasons.add(ie.getMessageObject());
        status = false;
      }
    // 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, configuration, false);
    } catch (InitializationException ie) {
      unacceptableReasons.add(ie.getMessageObject());
      status = false;
    }
    return status;
@@ -279,7 +258,7 @@
    // Instantiate the new class and initalize it.
    try
    {
      loadAndInstallEntryCache (newClassName, configuration);
      loadAndInstallEntryCache (newClassName);
    }
    catch (InitializationException ie)
    {
@@ -346,7 +325,7 @@
      String className = configuration.getEntryCacheClass();
      try
      {
        loadAndInstallEntryCache (className, configuration);
        loadAndInstallEntryCache (className);
      }
      catch (InitializationException ie)
      {
@@ -368,8 +347,6 @@
      List<Message> 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.
@@ -417,11 +394,28 @@
   *                                   to initialize the entry cache.
   */
  private void loadAndInstallEntryCache(
    String        className,
    EntryCacheCfg configuration
    String        className
    )
    throws InitializationException
  {
    EntryCacheCfg configuration;
    // Get the root configuration object.
    ServerManagementContext managementContext =
      ServerManagementContext.getInstance();
    RootCfg rootConfiguration =
      managementContext.getRootConfiguration();
    // Get the entry cache configuration.
    try {
      configuration = rootConfiguration.getEntryCache();
    } catch (ConfigException ce) {
      Message message = ERR_CONFIG_ENTRYCACHE_CANNOT_INITIALIZE_CACHE.get(
        className, (ce.getCause() != null ? ce.getCause().getMessage() :
          stackTraceToSingleLineString(ce)));
      throw new InitializationException(message, ce);
    }
    // Load the entry cache class...
    EntryCache entryCache = loadEntryCache (className, configuration, true);
@@ -464,7 +458,14 @@
      definition = EntryCacheCfgDefn.getInstance();
      propertyDefinition = definition.getEntryCacheClassPropertyDefinition();
      cacheClass = propertyDefinition.loadClass(className, EntryCache.class);
      cache = (EntryCache<? extends EntryCacheCfg>) cacheClass.newInstance();
      // If there is some entry cache instance already initialized work with
      // it instead of creating a new one unless explicit init is requested.
      if (initialize || (_entryCache == null)) {
        cache = (EntryCache<? extends EntryCacheCfg>) cacheClass.newInstance();
      } else {
        cache = (EntryCache<? extends EntryCacheCfg>) _entryCache;
      }
      if (initialize)
      {
@@ -474,7 +475,10 @@
            );
        method.invoke(cache, configuration);
      }
      else
      // This will check if configuration is acceptable on disabled
      // and uninitialized cache instance that has no "acceptable"
      // change listener registered to invoke and verify on its own.
      else if (!configuration.isEnabled())
      {
        Method method = cache.getClass().getMethod("isConfigurationAcceptable",
                                                   EntryCacheCfg.class,
@@ -507,9 +511,23 @@
    }
    catch (Exception e)
    {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      if (!initialize) {
        if (e instanceof InitializationException) {
          throw (InitializationException) e;
        } else {
          Message message = ERR_CONFIG_ENTRYCACHE_CONFIG_NOT_ACCEPTABLE.get(
            String.valueOf(configuration.dn()), e.getCause() != null ?
              e.getCause().getMessage() : stackTraceToSingleLineString(e));
          throw new InitializationException(message);
        }
      }
      Message message = ERR_CONFIG_ENTRYCACHE_CANNOT_INITIALIZE_CACHE.get(
          className,
          String.valueOf(configuration.dn()));
        className, (e.getCause() != null ? e.getCause().getMessage() :
          stackTraceToSingleLineString(e)));
      throw new InitializationException(message, e);
    }
  }
opends/src/server/org/opends/server/extensions/EntryCacheCommon.java
@@ -95,6 +95,10 @@
    // or PHASE_APPLY.
    private boolean _isAcceptable;
    // Indicates whether administrative action is required or not. Used when
    // _configPhase is PHASE_APPLY.
    private boolean _isAdminActionRequired;
    /**
     * Create an error handler.
     *
@@ -111,11 +115,12 @@
        ArrayList<Message>            errorMessages
        )
    {
      _configPhase         = configPhase;
      _unacceptableReasons = unacceptableReasons;
      _errorMessages       = errorMessages;
      _resultCode          = ResultCode.SUCCESS;
      _isAcceptable        = true;
      _configPhase           = configPhase;
      _unacceptableReasons   = unacceptableReasons;
      _errorMessages         = errorMessages;
      _resultCode            = ResultCode.SUCCESS;
      _isAcceptable          = true;
      _isAdminActionRequired = false;
    }
    /**
@@ -135,6 +140,49 @@
      {
      case PHASE_INIT:
        {
        _errorMessages.add (error);
        _isAcceptable = isAcceptable;
        break;
        }
      case PHASE_ACCEPTABLE:
        {
        _unacceptableReasons.add (error);
        _isAcceptable = isAcceptable;
        break;
        }
      case PHASE_APPLY:
        {
        _errorMessages.add (error);
        _isAcceptable = isAcceptable;
        if (_resultCode == ResultCode.SUCCESS)
        {
          _resultCode = resultCode;
        }
        break;
        }
      }
    }
    /**
     * Report an error.
     *
     * @param error        the error to report
     * @param isAcceptable <code>true</code> if the configuration is acceptable
     * @param resultCode   the change result for the current configuration
     * @param isAdminActionRequired <code>true</code> if administrative action
     *                              is required or <code>false</code> otherwise
     */
    public void reportError(
            Message error,
            boolean isAcceptable,
            ResultCode resultCode,
            boolean isAdminActionRequired
    )
    {
      switch (_configPhase)
      {
      case PHASE_INIT:
        {
        logError (error);
        break;
        }
@@ -152,6 +200,7 @@
        {
          _resultCode = resultCode;
        }
        _isAdminActionRequired = isAdminActionRequired;
        break;
        }
      }
@@ -212,6 +261,17 @@
    {
      return _configPhase;
    }
    /**
     * Get the current isAdminActionRequired flag as determined after apply
     * action has been taken on a given configuration.
     *
     * @return the isAdminActionRequired flag
     */
    public boolean getIsAdminActionRequired()
    {
      return _isAdminActionRequired;
    }
  } // ConfigErrorHandler
opends/src/server/org/opends/server/extensions/FIFOEntryCache.java
@@ -58,10 +58,10 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.util.ServerConstants;
import org.opends.messages.MessageBuilder;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.util.ServerConstants.*;
@@ -142,6 +142,9 @@
  // The maximum number of entries that may be held in the cache.
  private long maxEntries;
  // Currently registered configuration object.
  private FIFOEntryCacheCfg registeredConfiguration;
  static
@@ -175,6 +178,7 @@
      )
      throws ConfigException, InitializationException
  {
    registeredConfiguration = configuration;
    configuration.addFIFOChangeListener (this);
    configEntryDN = configuration.dn();
@@ -186,11 +190,24 @@
    // Read configuration and apply changes.
    boolean applyChanges = true;
    ArrayList<Message> errorMessages = new ArrayList<Message>();
    EntryCacheCommon.ConfigErrorHandler errorHandler =
      EntryCacheCommon.getConfigErrorHandler (
          EntryCacheCommon.ConfigPhase.PHASE_INIT, null, null
          EntryCacheCommon.ConfigPhase.PHASE_INIT, null, errorMessages
          );
    processEntryCacheConfig (configuration, applyChanges, errorHandler);
    if (!processEntryCacheConfig(configuration, applyChanges, errorHandler)) {
      MessageBuilder buffer = new MessageBuilder();
      if (!errorMessages.isEmpty()) {
        Iterator<Message> iterator = errorMessages.iterator();
        buffer.append(iterator.next());
        while (iterator.hasNext()) {
          buffer.append(".  ");
          buffer.append(iterator.next());
        }
      }
      Message message = ERR_FIFOCACHE_CANNOT_INITIALIZE.get(buffer.toString());
      throw new ConfigException(message);
    }
  }
@@ -200,9 +217,11 @@
   */
  public void finalizeEntryCache()
  {
    // Release all memory currently in use by this cache.
    cacheLock.lock();
    registeredConfiguration.removeFIFOChangeListener (this);
    // Release all memory currently in use by this cache.
    try
    {
      idMap.clear();
@@ -911,10 +930,13 @@
      EntryCacheCommon.getConfigErrorHandler (
          EntryCacheCommon.ConfigPhase.PHASE_APPLY, null, errorMessages
          );
    processEntryCacheConfig (configuration, applyChanges, errorHandler);
    // Do not apply changes unless this cache is enabled.
    if (configuration.isEnabled()) {
      processEntryCacheConfig (configuration, applyChanges, errorHandler);
    }
    boolean adminActionRequired = false;
    boolean adminActionRequired = errorHandler.getIsAdminActionRequired();
    ConfigChangeResult changeResult = new ConfigChangeResult(
        errorHandler.getResultCode(),
        adminActionRequired,
@@ -1007,8 +1029,8 @@
   * @param applyChanges   If true then take into account the new configuration.
   * @param errorHandler   An handler used to report errors.
   *
   * @return  The mapping between strings of character set values and the
   *          minimum number of characters required from those sets.
   * @return  <CODE>true</CODE> if configuration is acceptable,
   *          or <CODE>false</CODE> otherwise.
   */
  public boolean processEntryCacheConfig(
      FIFOEntryCacheCfg                   configuration,
@@ -1083,6 +1105,8 @@
      setLockTimeout(newLockTimeout);
      setIncludeFilters(newIncludeFilters);
      setExcludeFilters(newExcludeFilters);
      registeredConfiguration = configuration;
    }
    return errorHandler.getIsAcceptable();
opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java
@@ -29,11 +29,14 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -54,19 +57,21 @@
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.StatsConfig;
import com.sleepycat.je.config.ConfigParam;
import com.sleepycat.je.config.EnvironmentParams;
import org.opends.messages.MessageBuilder;
import org.opends.server.api.Backend;
import org.opends.server.api.EntryCache;
import org.opends.server.admin.std.server.EntryCacheCfg;
import org.opends.server.admin.std.server.FileSystemEntryCacheCfg;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.backends.jeb.ConfigurableEnvironment;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.EntryEncodeConfig;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
@@ -75,12 +80,13 @@
import org.opends.server.types.OpenDsException;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.util.ServerConstants;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.messages.ConfigMessages.*;
/**
 * This class defines a Directory Server entry cache that uses JE database to
@@ -193,16 +199,6 @@
  private static final String INDEXCLASSDBNAME = "IndexClassDB";
  private static final String INDEXKEY = "EntryCacheIndex";
  // JE config constants.
  // TODO: All hardcoded for now but we need to use a common
  // ds-cfg-je-property like multi-valued attribute for this, see Issue 1481.
  private static final Long JEBYTESINTERVAL = 10485760L;
  private static final Long JELOGFILEMAX = 10485760L;
  private static final Integer JEMINFILEUTILIZATION = 50;
  private static final Integer JEMINUTILIZATION = 90;
  private static final Integer JEMAXBATCHFILES = 1;
  private static final Integer JEMINAGE = 1;
  // The number of milliseconds between persistent state save/restore
  // progress reports.
  private long progressInterval = 5000;
@@ -215,11 +211,26 @@
  private EntryEncodeConfig encodeConfig =
    new EntryEncodeConfig(true, false, false);
  // JE native properties to configuration attributes map.
  private HashMap<String, String> configAttrMap =
    new HashMap<String, String>();
  // Currently registered configuration object.
  private FileSystemEntryCacheCfg registeredConfiguration;
  /**
   * Creates a new instance of this entry cache.
   */
  public FileSystemEntryCache() {
    super();
    // Register all JE native properties that map to
    // corresponding config attributes.
    configAttrMap.put("je.maxMemoryPercent",
      ConfigurableEnvironment.ATTR_DATABASE_CACHE_PERCENT);
    configAttrMap.put("je.maxMemory",
      ConfigurableEnvironment.ATTR_DATABASE_CACHE_SIZE);
    // All initialization should be performed in the initializeEntryCache.
  }
@@ -229,16 +240,30 @@
  public void initializeEntryCache(FileSystemEntryCacheCfg configuration)
          throws ConfigException, InitializationException {
    registeredConfiguration = configuration;
    configuration.addFileSystemChangeListener (this);
    configEntryDN = configuration.dn();
    // Read and apply configuration.
    boolean applyChanges = true;
    ArrayList<Message> errorMessages = new ArrayList<Message>();
    EntryCacheCommon.ConfigErrorHandler errorHandler =
      EntryCacheCommon.getConfigErrorHandler (
          EntryCacheCommon.ConfigPhase.PHASE_INIT, null, null
          EntryCacheCommon.ConfigPhase.PHASE_INIT, null, errorMessages
          );
    processEntryCacheConfig(configuration, applyChanges, errorHandler);
    if (!processEntryCacheConfig(configuration, applyChanges, errorHandler)) {
      MessageBuilder buffer = new MessageBuilder();
      if (!errorMessages.isEmpty()) {
        Iterator<Message> iterator = errorMessages.iterator();
        buffer.append(iterator.next());
        while (iterator.hasNext()) {
          buffer.append(".  ");
          buffer.append(iterator.next());
        }
      }
      Message message = ERR_FSCACHE_CANNOT_INITIALIZE.get(buffer.toString());
      throw new ConfigException(message);
    }
    // Set the cache type.
    if (cacheType.equalsIgnoreCase("LRU")) {
@@ -273,9 +298,6 @@
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      // Log an error message.
      logError(ERR_FSCACHE_HOMELESS.get());
      // Not having any home directory for the cache db environment is a
      // fatal error as we are unable to continue any further without it.
      Message message =
@@ -283,65 +305,10 @@
      throw new InitializationException(message, e);
    }
    // Open JE environment and cache database.
    // Configure and open JE environment and cache database.
    try {
      entryCacheEnvConfig = new EnvironmentConfig();
      // All these environment properties are cranked up to their extreme
      // values, either max or min, to get the smallest space consumption,
      // which turns into memory consumption for memory based filesystems,
      // possible. This will negate the performance somewhat but preserves
      // the memory to a much greater extent.
      //
      // TODO: All these options should be configurable, see Issue 1481.
      //
      entryCacheEnvConfig.setConfigParam("je.log.fileMax",
          JELOGFILEMAX.toString());
      entryCacheEnvConfig.setConfigParam("je.cleaner.minUtilization",
          JEMINUTILIZATION.toString());
      entryCacheEnvConfig.setConfigParam("je.cleaner.maxBatchFiles",
          JEMAXBATCHFILES.toString());
      entryCacheEnvConfig.setConfigParam("je.cleaner.minAge",
          JEMINAGE.toString());
      entryCacheEnvConfig.setConfigParam("je.cleaner.minFileUtilization",
          JEMINFILEUTILIZATION.toString());
      entryCacheEnvConfig.setConfigParam("je.checkpointer.bytesInterval",
          JEBYTESINTERVAL.toString());
      entryCacheEnvConfig.setAllowCreate(true);
      entryCacheEnv = new Environment(new File(cacheHome), entryCacheEnvConfig);
      // Set JE cache percent and size where the size value will prevail if set.
      entryCacheEnvMutableConfig = new EnvironmentMutableConfig();
      if (jeCachePercent != 0) {
        try {
          entryCacheEnvMutableConfig.setCachePercent(jeCachePercent);
        } catch (IllegalArgumentException e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          // Its safe to ignore and continue here, JE will use its default
          // value for this however we have to let the user know about it
          // so just log an error message.
          logError(ERR_FSCACHE_CANNOT_SET_JE_MEMORY_PCT.get());
        }
      }
      if (jeCacheSize != 0) {
        try {
          entryCacheEnvMutableConfig.setCacheSize(jeCacheSize);
        } catch (IllegalArgumentException e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          // Its safe to ignore and continue here, JE will use its default
          // value for this however we have to let the user know about it
          // so just log an error message.
          logError(ERR_FSCACHE_CANNOT_SET_JE_MEMORY_SIZE.get());
        }
      }
      entryCacheEnv.setMutableConfig(entryCacheEnvMutableConfig);
      entryCacheDBConfig = new DatabaseConfig();
      entryCacheDBConfig.setAllowCreate(true);
@@ -513,7 +480,9 @@
      }
      Message message =
          ERR_FSCACHE_CANNOT_INITIALIZE.get();
          ERR_FSCACHE_CANNOT_INITIALIZE.get(
          (e.getCause() != null ? e.getCause().getMessage() :
            stackTraceToSingleLineString(e)));
      throw new InitializationException(message, e);
    }
@@ -526,6 +495,8 @@
    cacheWriteLock.lock();
    registeredConfiguration.removeFileSystemChangeListener (this);
    // Store index/maps in case of persistent cache. Since the cache database
    // already exist at this point all we have to do is to serialize cache
    // index maps @see FileSystemEntryCacheIndex and put them under indexkey
@@ -1076,10 +1047,13 @@
      EntryCacheCommon.getConfigErrorHandler (
          EntryCacheCommon.ConfigPhase.PHASE_APPLY, null, errorMessages
          );
    processEntryCacheConfig (configuration, applyChanges, errorHandler);
    // Do not apply changes unless this cache is enabled.
    if (configuration.isEnabled()) {
      processEntryCacheConfig (configuration, applyChanges, errorHandler);
    }
    boolean adminActionRequired = false;
    boolean adminActionRequired = errorHandler.getIsAdminActionRequired();
    ConfigChangeResult changeResult = new ConfigChangeResult(
        errorHandler.getResultCode(),
        adminActionRequired,
@@ -1188,8 +1162,8 @@
   * @param applyChanges   If true then take into account the new configuration.
   * @param errorHandler   An handler used to report errors.
   *
   * @return  The mapping between strings of character set values and the
   *          minimum number of characters required from those sets.
   * @return  <CODE>true</CODE> if configuration is acceptable,
   *          or <CODE>false</CODE> otherwise.
   */
  public boolean processEntryCacheConfig(
      FileSystemEntryCacheCfg             configuration,
@@ -1198,18 +1172,24 @@
      )
  {
    // Local variables to read configuration.
    DN                    newConfigEntryDN;
    long                  newLockTimeout;
    long                  newMaxEntries;
    long                  newMaxAllowedMemory;
    HashSet<SearchFilter> newIncludeFilters = null;
    HashSet<SearchFilter> newExcludeFilters = null;
    int                   newJECachePercent;
    long                  newJECacheSize;
    boolean               newPersistentCache;
    boolean               newCompactEncoding;
    String                newCacheType = DEFAULT_FSCACHE_TYPE;
    String                newCacheHome = DEFAULT_FSCACHE_HOME;
    DN                       newConfigEntryDN;
    long                     newLockTimeout;
    long                     newMaxEntries;
    long                     newMaxAllowedMemory;
    HashSet<SearchFilter>    newIncludeFilters = null;
    HashSet<SearchFilter>    newExcludeFilters = null;
    int                      newJECachePercent;
    long                     newJECacheSize;
    boolean                  newPersistentCache;
    boolean                  newCompactEncoding;
    String                   newCacheType = DEFAULT_FSCACHE_TYPE;
    String                   newCacheHome = DEFAULT_FSCACHE_HOME;
    SortedSet<String>        newJEProperties;
    EnvironmentMutableConfig newMutableEnvConfig =
      new EnvironmentMutableConfig();
    EnvironmentConfig        newEnvConfig =
      new EnvironmentConfig();
    // Read configuration.
    newConfigEntryDN = configuration.dn();
@@ -1237,6 +1217,9 @@
    // Check if this cache should use compact encoding.
    newCompactEncoding = configuration.isBackendCompactEncoding();
    // Get native JE properties.
    newJEProperties = configuration.getJEProperty();
    switch (errorHandler.getConfigPhase())
    {
    case PHASE_INIT:
@@ -1260,6 +1243,45 @@
          errorHandler,
          configEntryDN
          );
      // JE configuration properties.
      try {
        newMutableEnvConfig.setCachePercent((newJECachePercent != 0 ?
          newJECachePercent :
          EnvironmentConfig.DEFAULT.getCachePercent()));
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        errorHandler.reportError(
          ERR_FSCACHE_CANNOT_SET_JE_MEMORY_PCT.get(),
          false,
          DirectoryServer.getServerErrorResultCode()
          );
      }
      try {
        newMutableEnvConfig.setCacheSize(newJECacheSize);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        errorHandler.reportError(
          ERR_FSCACHE_CANNOT_SET_JE_MEMORY_SIZE.get(),
          false,
          DirectoryServer.getServerErrorResultCode()
          );
      }
      // JE native properties.
      try {
        newEnvConfig = ConfigurableEnvironment.setJEProperties(
          newEnvConfig, newJEProperties, configAttrMap);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        errorHandler.reportError(
          ERR_FSCACHE_CANNOT_SET_JE_PROPERTIES.get(e.getMessage()),
          false, DirectoryServer.getServerErrorResultCode());
      }
      break;
    case PHASE_ACCEPTABLE:  // acceptable and apply are using the same
    case PHASE_APPLY:       // error ID codes
@@ -1277,6 +1299,54 @@
          errorHandler,
          configEntryDN
          );
      // Iterate through native JE properties.
      try {
        Map paramsMap = EnvironmentParams.SUPPORTED_PARAMS;
        // If this entry cache is disabled then there is no open JE
        // environment to check against, skip mutable check if so.
        if (configuration.isEnabled()) {
          newMutableEnvConfig =
            ConfigurableEnvironment.setJEProperties(
            entryCacheEnv.getConfig(), newJEProperties, configAttrMap);
          EnvironmentConfig oldEnvConfig = entryCacheEnv.getConfig();
          for (String jeEntry : newJEProperties) {
            // There is no need to validate properties yet again.
            StringTokenizer st = new StringTokenizer(jeEntry, "=");
            if (st.countTokens() == 2) {
              String jePropertyName = st.nextToken();
              String jePropertyValue = st.nextToken();
              ConfigParam param = (ConfigParam) paramsMap.get(jePropertyName);
              if (!param.isMutable()) {
                String oldValue = oldEnvConfig.getConfigParam(param.getName());
                String newValue = jePropertyValue;
                if (!oldValue.equalsIgnoreCase(newValue)) {
                  Message message =
                    INFO_CONFIG_JE_PROPERTY_REQUIRES_RESTART.get(
                    jePropertyName);
                  errorHandler.reportError(message, true, ResultCode.SUCCESS,
                    true);
                  if (debugEnabled()) {
                    TRACER.debugInfo("The change to the following property " +
                      "will take effect when the component is restarted: " +
                      jePropertyName);
                  }
                }
              }
            }
          }
        } else {
          newMutableEnvConfig =
            ConfigurableEnvironment.setJEProperties(
            new EnvironmentConfig(), newJEProperties, configAttrMap);
        }
      } catch (ConfigException ce) {
        errorHandler.reportError(ce.getMessageObject(),
          false, DirectoryServer.getServerErrorResultCode());
      } catch (Exception e) {
        errorHandler.reportError(
          Message.raw(stackTraceToSingleLineString(e)),
          false, DirectoryServer.getServerErrorResultCode());
      }
      break;
    }
@@ -1284,19 +1354,19 @@
    {
      switch (errorHandler.getConfigPhase()) {
      case PHASE_INIT:
        cacheType      = newCacheType;
        cacheHome      = newCacheHome;
        jeCachePercent = newJECachePercent;
        jeCacheSize    = newJECacheSize;
        cacheType = newCacheType;
        cacheHome = newCacheHome;
        entryCacheEnvConfig = newEnvConfig;
        entryCacheEnvMutableConfig = newMutableEnvConfig;
        break;
      case PHASE_APPLY:
        jeCachePercent = newJECachePercent;
        try {
            EnvironmentMutableConfig envConfig =
            newMutableEnvConfig =
              entryCacheEnv.getMutableConfig();
            envConfig.setCachePercent((jeCachePercent != 0 ? jeCachePercent :
            newMutableEnvConfig.setCachePercent((newJECachePercent != 0 ?
              newJECachePercent :
              EnvironmentConfig.DEFAULT.getCachePercent()));
            entryCacheEnv.setMutableConfig(envConfig);
            entryCacheEnv.setMutableConfig(newMutableEnvConfig);
            entryCacheEnv.evictMemory();
        } catch (Exception e) {
            if (debugEnabled()) {
@@ -1308,12 +1378,11 @@
              DirectoryServer.getServerErrorResultCode()
              );
        }
        jeCacheSize = newJECacheSize;
        try {
            EnvironmentMutableConfig envConfig =
            newMutableEnvConfig =
              entryCacheEnv.getMutableConfig();
            envConfig.setCacheSize(jeCacheSize);
            entryCacheEnv.setMutableConfig(envConfig);
            newMutableEnvConfig.setCacheSize(newJECacheSize);
            entryCacheEnv.setMutableConfig(newMutableEnvConfig);
            entryCacheEnv.evictMemory();
        } catch (Exception e) {
            if (debugEnabled()) {
@@ -1325,6 +1394,23 @@
              DirectoryServer.getServerErrorResultCode()
              );
        }
        try {
          EnvironmentConfig oldEnvConfig = entryCacheEnv.getConfig();
          newEnvConfig = ConfigurableEnvironment.setJEProperties(
            oldEnvConfig, newJEProperties, configAttrMap);
          // This takes care of changes to the JE environment for those
          // properties that are mutable at runtime.
          entryCacheEnv.setMutableConfig(newEnvConfig);
        } catch (Exception e) {
          if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, e);
            }
            errorHandler.reportError(
              ERR_FSCACHE_CANNOT_SET_JE_PROPERTIES.get(e.getMessage()),
              false,
              DirectoryServer.getServerErrorResultCode()
              );
        }
        break;
      }
@@ -1339,6 +1425,8 @@
      setLockTimeout(newLockTimeout);
      setIncludeFilters(newIncludeFilters);
      setExcludeFilters(newExcludeFilters);
      registeredConfiguration = configuration;
    }
    return errorHandler.getIsAcceptable();
opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java
@@ -33,9 +33,11 @@
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.opends.messages.MessageBuilder;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.EntryCacheCfg;
@@ -58,7 +60,6 @@
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.util.ServerConstants.*;
@@ -100,10 +101,15 @@
  // reference is freed.
  private ReferenceQueue<CacheEntry> referenceQueue;
  // Currently registered configuration object.
  private SoftReferenceEntryCacheCfg registeredConfiguration;
  private Thread cleanerThread;
  private volatile boolean shutdown = false;
  static
  {
    timeUnits.put(TIME_UNIT_MILLISECONDS_ABBR, 1D);
@@ -148,6 +154,7 @@
      )
      throws ConfigException, InitializationException
  {
    registeredConfiguration = configuration;
    configuration.addSoftReferenceChangeListener (this);
    configEntryDN = configuration.dn();
@@ -156,11 +163,25 @@
    // Read configuration and apply changes.
    boolean applyChanges = true;
    ArrayList<Message> errorMessages = new ArrayList<Message>();
    EntryCacheCommon.ConfigErrorHandler errorHandler =
      EntryCacheCommon.getConfigErrorHandler (
          EntryCacheCommon.ConfigPhase.PHASE_INIT, null, null
          EntryCacheCommon.ConfigPhase.PHASE_INIT, null, errorMessages
          );
    processEntryCacheConfig (configuration, applyChanges, errorHandler);
    if (!processEntryCacheConfig(configuration, applyChanges, errorHandler)) {
      MessageBuilder buffer = new MessageBuilder();
      if (!errorMessages.isEmpty()) {
        Iterator<Message> iterator = errorMessages.iterator();
        buffer.append(iterator.next());
        while (iterator.hasNext()) {
          buffer.append(".  ");
          buffer.append(iterator.next());
        }
      }
      Message message = ERR_SOFTREFCACHE_CANNOT_INITIALIZE.get(
        buffer.toString());
      throw new ConfigException(message);
    }
  }
@@ -170,7 +191,10 @@
   */
  public synchronized void finalizeEntryCache()
  {
    registeredConfiguration.removeSoftReferenceChangeListener (this);
    shutdown = true;
    dnMap.clear();
    idMap.clear();
    if (cleanerThread != null) {
@@ -510,9 +534,12 @@
      EntryCacheCommon.getConfigErrorHandler (
          EntryCacheCommon.ConfigPhase.PHASE_APPLY, null, errorMessages
          );
    processEntryCacheConfig (configuration, applyChanges, errorHandler);
    // Do not apply changes unless this cache is enabled.
    if (configuration.isEnabled()) {
      processEntryCacheConfig (configuration, applyChanges, errorHandler);
    }
    boolean adminActionRequired = false;
    boolean adminActionRequired = errorHandler.getIsAdminActionRequired();
    ConfigChangeResult changeResult = new ConfigChangeResult(
        errorHandler.getResultCode(),
        adminActionRequired,
@@ -530,8 +557,8 @@
   * @param applyChanges   If true then take into account the new configuration.
   * @param errorHandler   An handler used to report errors.
   *
   * @return  The mapping between strings of character set values and the
   *          minimum number of characters required from those sets.
   * @return  <CODE>true</CODE> if configuration is acceptable,
   *          or <CODE>false</CODE> otherwise.
   */
  public boolean processEntryCacheConfig(
      SoftReferenceEntryCacheCfg          configuration,
@@ -594,6 +621,8 @@
      setLockTimeout(newLockTimeout);
      setIncludeFilters(newIncludeFilters);
      setExcludeFilters(newExcludeFilters);
      registeredConfiguration = configuration;
    }
    return errorHandler.getIsAcceptable();