From 90997a88f290bc77d77a7690d2adeadc3e91fdc1 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 07 Jan 2008 19:45:19 +0000
Subject: [PATCH] Fix issue 2462: NPE when changing index configuration while import ongoing

---
 opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java |  121 +++++++++++++++++------
 /dev/null                                                                         |  149 -----------------------------
 opends/src/server/org/opends/server/admin/server/ServerManagedObject.java         |    3 
 opends/src/server/org/opends/server/backends/jeb/EntryContainer.java              |   23 +++-
 4 files changed, 108 insertions(+), 188 deletions(-)

diff --git a/opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java b/opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java
deleted file mode 100644
index 5fe1092..0000000
--- a/opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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 2007 Sun Microsystems, Inc.
- */
-package org.opends.server.admin.server;
-import org.opends.messages.Message;
-
-
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.loggers.ErrorLogger.*;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.messages.AdminMessages;
-import org.opends.messages.MessageBuilder;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.ResultCode;
-import org.opends.server.util.StaticUtils;
-
-
-
-/**
- * A configuration delete listener which detects when a specified
- * entry is removed and, when it is, cleans up any listeners
- * associated with it.
- */
-final class CleanerConfigDeleteListener implements ConfigDeleteListener {
-
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  // The change listeners.
-  private Map<DN, ConfigChangeListener> changeListeners =
-    new HashMap<DN, ConfigChangeListener>();
-
-  // The DN of the monitored configuration entry.
-  private final DN dn;
-
-
-
-  /**
-   * Creates a new cleaner configuration change listener which will
-   * remove any registered listeners when then configuration entry it
-   * is monitoring is removed.
-   *
-   * @param dn
-   *          The DN of the entry to be monitored.
-   */
-  public CleanerConfigDeleteListener(DN dn) {
-    this.dn = dn;
-  }
-
-
-
-  /**
-   * Register a configuration change listener for removal when the
-   * monitored entry is removed.
-   *
-   * @param dn
-   *          The name of the entry associated with the configuration
-   *          change listener.
-   * @param listener
-   *          The configuration change listener.
-   */
-  public void addConfigChangeListener(DN dn, ConfigChangeListener listener) {
-    changeListeners.put(dn, listener);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
-    // Remove the listeners if the deleted entry is the monitored
-    // entry.
-    if (configEntry.getDN().equals(dn)) {
-      for (Map.Entry<DN, ConfigChangeListener> me :
-        changeListeners.entrySet()) {
-        ConfigEntry listenerConfigEntry = getConfigEntry(me.getKey());
-        if (listenerConfigEntry != null) {
-          listenerConfigEntry.deregisterChangeListener(me.getValue());
-        }
-      }
-
-      // Now remove this listener as we are no longer needed.
-      ConfigEntry parentConfigEntry = getConfigEntry(dn.getParent());
-      if (parentConfigEntry != null) {
-        parentConfigEntry.deregisterDeleteListener(this);
-      }
-    }
-
-    return new ConfigChangeResult(ResultCode.SUCCESS, false);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
-      MessageBuilder unacceptableReason) {
-    // Always acceptable.
-    return true;
-  }
-
-
-
-  // Returns the named configuration entry or null if it could not be
-  // retrieved.
-  private ConfigEntry getConfigEntry(DN dn) {
-    try {
-      ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
-      if (configEntry != null) {
-        return configEntry;
-      } else {
-        Message message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST.
-            get(String.valueOf(dn));
-        logError(message);
-      }
-    } catch (ConfigException e) {
-      // The dependent entry could not be retrieved.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = AdminMessages.ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get(
-          String.valueOf(dn), StaticUtils.getExceptionMessage(e));
-      logError(message);
-    }
-
-    return null;
-  }
-}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
index c4e4848..d5aee62 100644
--- a/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
+++ b/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2007 Sun Microsystems, Inc.
+ *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.admin.server;
 
@@ -54,6 +54,7 @@
 import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
 import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
 import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.api.ConfigDeleteListener;
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
@@ -202,12 +203,16 @@
   // Cached managed object between accept/apply call-backs.
   private ServerManagedObject<? extends S> cachedManagedObject;
 
+  // The delete listener which is used to remove this listener and any
+  // dependencies.
+  private final ConfigDeleteListener cleanerListener;
+
   // The names of entries that this change listener depends on.
   private final Set<DN> dependencies;
 
   // The listener used to notify this listener when dependency entries
   // are modified.
-  private final DependencyConfigChangeListener dependencyListener;
+  private final ConfigChangeListener dependencyListener;
 
   // The DN associated with this listener.
   private final DN dn;
@@ -239,14 +244,43 @@
     // are modified. Determine the dependencies and register change
     // listeners against them.
     this.dependencies = new HashSet<DN>();
-    this.dependencyListener = new DependencyConfigChangeListener(dn, this);
+    this.dependencyListener = new ConfigChangeListener() {
+
+      public ConfigChangeResult applyConfigurationChange(
+          ConfigEntry configEntry) {
+        ConfigEntry dependentConfigEntry = getConfigEntry(dn);
+        if (dependentConfigEntry != null) {
+          return ConfigChangeListenerAdaptor.this
+              .applyConfigurationChange(dependentConfigEntry);
+        } else {
+          // The dependent entry was not found.
+          configEntry.deregisterChangeListener(this);
+          return new ConfigChangeResult(ResultCode.SUCCESS, false);
+        }
+      }
+
+
+
+      public boolean configChangeIsAcceptable(ConfigEntry configEntry,
+          MessageBuilder unacceptableReason) {
+        ConfigEntry dependentConfigEntry = getConfigEntry(dn);
+        if (dependentConfigEntry != null) {
+          return ConfigChangeListenerAdaptor.this.configChangeIsAcceptable(
+              dependentConfigEntry, unacceptableReason, configEntry);
+        } else {
+          // The dependent entry was not found.
+          configEntry.deregisterChangeListener(this);
+          return true;
+        }
+      }
+
+    };
 
     AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
     for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
       Visitor.find(path, pd, dependencies);
     }
 
-    CleanerConfigDeleteListener cleaner = new CleanerConfigDeleteListener(dn);
     for (DN entryDN : dependencies) {
       // Be careful not to register listeners against the dependent
       // entry itself.
@@ -254,22 +288,40 @@
         ConfigEntry configEntry = getConfigEntry(entryDN);
         if (configEntry != null) {
           configEntry.registerChangeListener(dependencyListener);
-          cleaner.addConfigChangeListener(entryDN, dependencyListener);
         }
       }
     }
 
-    // Register a delete listener which will remove the dependency
-    // listeners when this entry is removed.
+    // Register a delete listener against the parent which will
+    // finalize this change listener when the monitored configuration
+    // entry is removed.
+    this.cleanerListener = new ConfigDeleteListener() {
 
-    // FIXME: we should really remove the dependency listeners when
-    // this listener is deregistered, but we have no way to track
-    // that.
+      public ConfigChangeResult applyConfigurationDelete(
+          ConfigEntry configEntry) {
+        // Perform finalization if the deleted entry is the monitored
+        // entry.
+        if (configEntry.getDN().equals(dn)) {
+          finalizeChangeListener();
+        }
+        return new ConfigChangeResult(ResultCode.SUCCESS, false);
+      }
+
+
+
+      public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
+          MessageBuilder unacceptableReason) {
+        // Always acceptable.
+        return true;
+      }
+
+    };
+
     DN parent = dn.getParent();
     if (parent != null) {
       ConfigEntry configEntry = getConfigEntry(dn.getParent());
       if (configEntry != null) {
-        configEntry.registerDeleteListener(cleaner);
+        configEntry.registerDeleteListener(cleanerListener);
       }
     }
   }
@@ -280,28 +332,7 @@
    * {@inheritDoc}
    */
   public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
-    return applyConfigurationChange(configEntry, configEntry);
-  }
-
-
-
-  /**
-   * Attempts to apply a new configuration to this Directory Server
-   * component based on the provided changed entry.
-   *
-   * @param configEntry
-   *          The configuration entry that containing the updated
-   *          configuration for this component.
-   * @param newConfigEntry
-   *          The configuration entry that caused the notification
-   *          (will be different from <code>configEntry</code> if a
-   *          dependency was modified).
-   * @return Information about the result of processing the
-   *         configuration change.
-   */
-  public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry,
-      ConfigEntry newConfigEntry) {
-    // TODO: looking at the ConfigFileHandler implementation reveals
+    // Looking at the ConfigFileHandler implementation reveals
     // that this ConfigEntry will actually be a different object to
     // the one passed in the previous call-back (it will have the same
     // content though). This configuration entry has the correct
@@ -396,6 +427,30 @@
 
 
   /**
+   * Finalizes this configuration change listener adaptor. This method
+   * must be called before this change listener is removed.
+   */
+  public void finalizeChangeListener() {
+    // Remove the dependency listeners.
+    for (DN dependency : dependencies) {
+      ConfigEntry listenerConfigEntry = getConfigEntry(dependency);
+      if (listenerConfigEntry != null) {
+        listenerConfigEntry.deregisterChangeListener(dependencyListener);
+      }
+    }
+
+    // Now remove the cleaner listener as it will no longer be
+    // needed.
+    ConfigEntry parentConfigEntry = getConfigEntry(dn.getParent());
+    if (parentConfigEntry != null) {
+      parentConfigEntry.deregisterDeleteListener(cleanerListener);
+    }
+
+  }
+
+
+
+  /**
    * Get the configuration change listener associated with this
    * adaptor.
    *
diff --git a/opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java b/opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java
deleted file mode 100644
index 588193e..0000000
--- a/opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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 2007 Sun Microsystems, Inc.
- */
-package org.opends.server.admin.server;
-
-
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.loggers.ErrorLogger.*;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.messages.AdminMessages;
-import org.opends.messages.MessageBuilder;
-import org.opends.messages.Message;
-
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.ResultCode;
-import org.opends.server.util.StaticUtils;
-
-
-
-/**
- * A configuration change listener which can be used to notify a
- * change listener when modifications are made to configuration
- * entries that it depends upon.
- */
-final class DependencyConfigChangeListener implements ConfigChangeListener {
-
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  // The DN of the dependent configuration entry.
-  private final DN dependentDN;
-
-  // The dependent configuration change listener adaptor.
-  private final ConfigChangeListenerAdaptor<?> dependentListener;
-
-
-
-  /**
-   * Creates a new dependency configuration change listener which will
-   * notify the dependent listener whenever the configuration entry
-   * that this listener monitors is modified.
-   *
-   * @param dependentDN
-   *          The DN of the dependent configuration entry.
-   * @param dependentListener
-   *          The dependent configuration change listener adaptor.
-   */
-  public DependencyConfigChangeListener(DN dependentDN,
-      ConfigChangeListenerAdaptor<?> dependentListener) {
-    this.dependentDN = dependentDN;
-    this.dependentListener = dependentListener;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
-    ConfigEntry dependentConfigEntry = getConfigEntry(dependentDN);
-    if (dependentConfigEntry != null) {
-      return dependentListener.applyConfigurationChange(dependentConfigEntry,
-          configEntry);
-    } else {
-      // The dependent entry was not found.
-      configEntry.deregisterChangeListener(this);
-      return new ConfigChangeResult(ResultCode.SUCCESS, false);
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean configChangeIsAcceptable(ConfigEntry configEntry,
-      MessageBuilder unacceptableReason) {
-    ConfigEntry dependentConfigEntry = getConfigEntry(dependentDN);
-    if (dependentConfigEntry != null) {
-      return dependentListener.configChangeIsAcceptable(dependentConfigEntry,
-          unacceptableReason, configEntry);
-    } else {
-      // The dependent entry was not found.
-      configEntry.deregisterChangeListener(this);
-      return true;
-    }
-  }
-
-
-
-  // Returns the named configuration entry or null if it could not be
-  // retrieved.
-  private ConfigEntry getConfigEntry(DN dn) {
-    try {
-      ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
-      if (configEntry != null) {
-        return configEntry;
-      } else {
-        Message message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST.
-            get(String.valueOf(dn));
-        logError(message);
-      }
-    } catch (ConfigException e) {
-      // The dependent entry could not be retrieved.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = AdminMessages.ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get(
-          String.valueOf(dn), StaticUtils.getExceptionMessage(e));
-      logError(message);
-    }
-
-    return null;
-  }
-
-}
diff --git a/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java b/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
index 89103c6..2b970a4 100644
--- a/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ *      Portions Copyright 2006-2008 Sun Microsystems, Inc.
  */
 
 package org.opends.server.admin.server;
@@ -185,6 +185,7 @@
         ConfigChangeListenerAdaptor<?> adaptor =
           (ConfigChangeListenerAdaptor<?>) l;
         if (adaptor.getConfigurationChangeListener() == listener) {
+          adaptor.finalizeChangeListener();
           configEntry.deregisterChangeListener(adaptor);
         }
       }
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 75143ae..9bc6038 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ *      Portions Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.backends.jeb;
 import org.opends.messages.Message;
@@ -551,11 +551,24 @@
   public void close()
       throws DatabaseException
   {
-    List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
-    listDatabases(databases);
-    for(DatabaseContainer db : databases)
+    // Close core indexes.
+    dn2id.close();
+    id2entry.close();
+    dn2uri.close();
+    id2children.close();
+    id2subtree.close();
+    state.close();
+
+    // Close attribute indexes and deregister any listeners.
+    for (AttributeIndex index : attrIndexMap.values())
     {
-      db.close();
+      index.close();
+    }
+
+    // Close VLV indexes and deregister any listeners.
+    for (VLVIndex vlvIndex : vlvIndexMap.values())
+    {
+      vlvIndex.close();
     }
 
     config.removeLocalDBChangeListener(this);

--
Gitblit v1.10.0