From b5ad7e2402d626b6df3745616e51e514eaec07e8 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Sat, 07 Jul 2007 21:19:53 +0000
Subject: [PATCH] Fix for issue 1558: null pointer exception at DS startup when using one-to-zero-or-one relation

---
 opendj-sdk/opends/src/server/org/opends/server/messages/AdminMessages.java                |   13 ++++
 opendj-sdk/opends/src/server/org/opends/server/admin/server/DelayedConfigAddListener.java |   13 +---
 opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java      |  106 +++++++++++++++++++++++++----------
 3 files changed, 92 insertions(+), 40 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/DelayedConfigAddListener.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/DelayedConfigAddListener.java
index 4233b02..7d8be0f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/DelayedConfigAddListener.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/DelayedConfigAddListener.java
@@ -77,8 +77,6 @@
    * Create a new delayed add listener which will register an add
    * listener with the specified entry when it is added.
    *
-   * @param parent
-   *          The name of the parent entry.
    * @param child
    *          The name of the subordinate entry which should have an
    *          add listener registered with it when it is created.
@@ -86,9 +84,8 @@
    *          The add listener to be added to the subordinate entry
    *          when it is added.
    */
-  public DelayedConfigAddListener(DN parent, DN child,
-      ConfigAddListener addListener) {
-    this.parent = parent;
+  public DelayedConfigAddListener(DN child, ConfigAddListener addListener) {
+    this.parent = child.getParent();
     this.child = child;
     this.delayedAddListener = addListener;
     this.delayedDeleteListener = null;
@@ -100,8 +97,6 @@
    * Create a new delayed add listener which will register a delete
    * listener with the specified entry when it is added.
    *
-   * @param parent
-   *          The name of the parent entry.
    * @param child
    *          The name of the subordinate entry which should have a
    *          delete listener registered with it when it is created.
@@ -109,9 +104,9 @@
    *          The delete listener to be added to the subordinate entry
    *          when it is added.
    */
-  public DelayedConfigAddListener(DN parent, DN child,
+  public DelayedConfigAddListener(DN child,
       ConfigDeleteListener deleteListener) {
-    this.parent = parent;
+    this.parent = child.getParent();
     this.child = child;
     this.delayedAddListener = null;
     this.delayedDeleteListener = deleteListener;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
index 6cc2865..f4c3b0c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
@@ -956,21 +956,10 @@
       ConfigurationAddListener<M> listener) throws IllegalArgumentException,
       ConfigException {
     validateRelationDefinition(d);
-
     DN baseDN = DNBuilder.create(path, d);
-    ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
     ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d,
         listener);
-
-    if (relationEntry != null) {
-      relationEntry.registerAddListener(adaptor);
-    } else {
-      // The relation entry does not exist yet so register a delayed
-      // add listener.
-      ConfigAddListener delayedListener = new DelayedConfigAddListener(
-          configEntry.getDN(), baseDN, adaptor);
-      configEntry.registerAddListener(delayedListener);
-    }
+    registerAddListener(baseDN, adaptor);
   }
 
 
@@ -988,15 +977,18 @@
    * @throws IllegalArgumentException
    *           If the optional relation definition is not associated
    *           with this managed object's definition.
+   * @throws ConfigException
+   *           If the configuration entry associated with the
+   *           optional relation could not be retrieved.
    */
   public <M extends Configuration> void registerAddListener(
       OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener)
-      throws IllegalArgumentException {
+      throws IllegalArgumentException, ConfigException {
     validateRelationDefinition(d);
-
+    DN baseDN = DNBuilder.create(path);
     ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d,
         listener);
-    configEntry.registerAddListener(adaptor);
+    registerAddListener(baseDN, adaptor);
   }
 
 
@@ -1039,21 +1031,10 @@
       ConfigurationDeleteListener<M> listener) throws IllegalArgumentException,
       ConfigException {
     validateRelationDefinition(d);
-
     DN baseDN = DNBuilder.create(path, d);
-    ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
     ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d,
         listener);
-
-    if (relationEntry != null) {
-      relationEntry.registerDeleteListener(adaptor);
-    } else {
-      // The relation entry does not exist yet so register a delayed
-      // add listener.
-      ConfigAddListener delayedListener = new DelayedConfigAddListener(
-          configEntry.getDN(), baseDN, adaptor);
-      configEntry.registerAddListener(delayedListener);
-    }
+    registerDeleteListener(baseDN, adaptor);
   }
 
 
@@ -1071,15 +1052,19 @@
    * @throws IllegalArgumentException
    *           If the optional relation definition is not associated
    *           with this managed object's definition.
+   * @throws ConfigException
+   *           If the configuration entry associated with the
+   *           optional relation could not be retrieved.
    */
   public <M extends Configuration> void registerDeleteListener(
       OptionalRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
+      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException,
+      ConfigException {
     validateRelationDefinition(d);
-
+    DN baseDN = DNBuilder.create(path);
     ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d,
         listener);
-    configEntry.registerDeleteListener(adaptor);
+    registerDeleteListener(baseDN, adaptor);
   }
 
 
@@ -1193,6 +1178,67 @@
 
 
 
+  // Register an instantiable or optional relation add listener.
+  private void registerAddListener(DN baseDN, ConfigAddListener adaptor)
+      throws IllegalArgumentException, ConfigException {
+    ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
+
+    if (relationEntry != null) {
+      relationEntry.registerAddListener(adaptor);
+    } else {
+      // The relation entry does not exist yet so register a delayed
+      // add listener.
+      ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN,
+          adaptor);
+      registerDelayedListener(baseDN, delayedListener);
+    }
+  }
+
+
+
+  // Register a delayed listener with the nearest existing parent
+  // entry to the provided base DN.
+  private void registerDelayedListener(DN baseDN,
+      ConfigAddListener delayedListener) throws ConfigException {
+    DN parentDN = baseDN.getParent();
+    while (parentDN != null) {
+      ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
+      if (relationEntry == null) {
+        delayedListener = new DelayedConfigAddListener(parentDN,
+            delayedListener);
+        parentDN = parentDN.getParent();
+      } else {
+        configEntry.registerAddListener(delayedListener);
+        return;
+      }
+    }
+
+    // No parent entry could be found.
+    int msgID = AdminMessages.MSGID_ADMIN_UNABLE_TO_REGISTER_LISTENER;
+    String message = getMessage(msgID, String.valueOf(baseDN));
+    throw new ConfigException(msgID, message);
+  }
+
+
+
+  // Register an instantiable or optional relation delete listener.
+  private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor)
+      throws ConfigException {
+    ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
+
+    if (relationEntry != null) {
+      relationEntry.registerDeleteListener(adaptor);
+    } else {
+      // The relation entry does not exist yet so register a delayed
+      // add listener.
+      ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN,
+          adaptor);
+      registerDelayedListener(baseDN, delayedListener);
+    }
+  }
+
+
+
   // Validate that a relation definition belongs to this managed
   // object.
   private void validateRelationDefinition(RelationDefinition<?, ?> rd)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/AdminMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/AdminMessages.java
index 6b939d7..eb27982 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/AdminMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/AdminMessages.java
@@ -483,6 +483,15 @@
   public static final int MSGID_ADMIN_ARG_BACKENDNAME_DESCRIPTION =
     CATEGORY_MASK_ADMIN | SEVERITY_MASK_INFORMATIONAL | 56;
 
+  /**
+   * The message ID for the message that will be used if an add or
+   * delete listener cannot be registered because the base entry does
+   * not exist and it does not have any ancestor entries. This takes a
+   * single argument which is the name of the base entry.
+   */
+  public static final int MSGID_ADMIN_UNABLE_TO_REGISTER_LISTENER =
+    CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 57;
+
   // Prevent instantiation.
   private AdminMessages() {
     // Do nothing.
@@ -656,6 +665,8 @@
     registerMessage(MSGID_ADMIN_ARG_BACKENDNAME_DESCRIPTION,
         "The backen name is which the admin data will be registered. " +
         "This is a required argument");
-
+    registerMessage(MSGID_ADMIN_UNABLE_TO_REGISTER_LISTENER,
+        "Unable to register an add/delete listener against the entry %s " +
+        "because it does not exist in the configuration");
   }
 }

--
Gitblit v1.10.0