From 5d6e9428fedead57a9c9438cebe58b485ff476d2 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 14 Sep 2007 10:22:17 +0000
Subject: [PATCH] Avoid managed object definition initialization dependency problems. Using features like inherited default values and aggregation properties it is quite straightforward to encounter initialization dependency problems. For example: the global configuration will contain an aggregation property which references the default password policy. This aggregation definition is defined using a managed object path which, when decoded, contains a reference to the root configuration and its "password-policy" relation. This is what happens during initialization of the root configuration:

---
 opends/src/server/org/opends/server/admin/ClassLoaderProvider.java |  118 +++++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 71 insertions(+), 47 deletions(-)

diff --git a/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java b/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java
index 2de3b1d..4dcd284 100644
--- a/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java
+++ b/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java
@@ -25,15 +25,13 @@
  *      Portions Copyright 2007 Sun Microsystems, Inc.
  */
 package org.opends.server.admin;
-import org.opends.messages.Message;
 
 
 
-import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.messages.AdminMessages.*;
-import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.util.StaticUtils.*;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -41,6 +39,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -52,8 +51,10 @@
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
+import org.opends.messages.Message;
 import org.opends.server.admin.std.meta.RootCfgDefn;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.InitializationException;
 import org.opends.server.util.Validator;
@@ -474,21 +475,13 @@
 
     try {
       loadDefinitionClasses(is);
-    } catch (IOException e) {
+    } catch (InitializationException e) {
       if (debugEnabled()) {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
 
-      Message message = ERR_ADMIN_CANNOT_READ_CORE_MANIFEST.get(
-          CORE_MANIFEST, stackTraceToSingleLineString(e));
-      throw new InitializationException(message);
-    } catch (Exception e) {
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_ADMIN_CANNOT_LOAD_CLASS_FROM_CORE_MANIFEST.get(
-          CORE_MANIFEST, stackTraceToSingleLineString(e));
+      Message message = ERR_CLASS_LOADER_CANNOT_LOAD_CORE.get(CORE_MANIFEST,
+          stackTraceToSingleLineString(e));
       throw new InitializationException(message);
     }
   }
@@ -519,31 +512,21 @@
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
 
-        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.
-            get(EXTENSION_MANIFEST, jarFile.getName(),
-                stackTraceToSingleLineString(e));
+        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.get(
+            EXTENSION_MANIFEST, jarFile.getName(),
+            stackTraceToSingleLineString(e));
         throw new InitializationException(message);
       }
 
       try {
         loadDefinitionClasses(is);
-      } catch (IOException e) {
+      } catch (InitializationException e) {
         if (debugEnabled()) {
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
 
-        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.
-            get(EXTENSION_MANIFEST, jarFile.getName(),
-                stackTraceToSingleLineString(e));
-        throw new InitializationException(message);
-      } catch (Exception e) {
-        if (debugEnabled()) {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message = ERR_ADMIN_CANNOT_LOAD_CLASS_FROM_EXTENSION_MANIFEST.
-            get(EXTENSION_MANIFEST, jarFile.getName(),
-                stackTraceToSingleLineString(e));
+        Message message = ERR_CLASS_LOADER_CANNOT_LOAD_EXTENSION.get(jarFile
+            .getName(), EXTENSION_MANIFEST, stackTraceToSingleLineString(e));
         throw new InitializationException(message);
       }
     }
@@ -557,24 +540,25 @@
    *
    * @param is
    *          The manifest file input stream.
-   * @throws IOException
-   *           If an IO error occurred whilst reading the manifest
-   *           file.
-   * @throws ClassNotFoundException
-   *           If an IO error occurred whilst reading the manifest
-   *           file.
-   * @throws LinkageError
-   *           If the linkage fails.
-   * @throws ExceptionInInitializerError
-   *           If the initialization provoked by this method fails.
+   * @throws InitializationException
+   *           If the definition classes could not be loaded and
+   *           initialized.
    */
   private void loadDefinitionClasses(InputStream is)
-      throws IOException, ClassNotFoundException, LinkageError,
-      ExceptionInInitializerError {
+      throws InitializationException {
     BufferedReader reader = new BufferedReader(new InputStreamReader(
         is));
+    List<AbstractManagedObjectDefinition<?, ?>> definitions =
+      new LinkedList<AbstractManagedObjectDefinition<?,?>>();
     while (true) {
-      String className = reader.readLine();
+      String className;
+      try {
+        className = reader.readLine();
+      } catch (IOException e) {
+        Message msg = ERR_CLASS_LOADER_CANNOT_READ_MANIFEST_FILE.get(String
+            .valueOf(e.getMessage()));
+        throw new InitializationException(msg, e);
+      }
 
       // Break out when the end of the manifest is reached.
       if (className == null) {
@@ -594,8 +578,48 @@
 
       TRACER.debugMessage(DebugLogLevel.INFO, "Loading class " + className);
 
-      // Use the underlying loader.
-      Class.forName(className, true, loader);
+      // Load the class and get an instance of it if it is a definition.
+      Class<?> theClass;
+      try {
+        theClass = Class.forName(className, true, loader);
+      } catch (Exception e) {
+        Message msg = ERR_CLASS_LOADER_CANNOT_LOAD_CLASS.get(className, String
+            .valueOf(e.getMessage()));
+        throw new InitializationException(msg, e);
+      }
+      if (AbstractManagedObjectDefinition.class.isAssignableFrom(theClass)) {
+        // We need to instantiate it using its getInstance() static method.
+        Method method;
+        try {
+          method = theClass.getMethod("getInstance");
+        } catch (Exception e) {
+          Message msg = ERR_CLASS_LOADER_CANNOT_FIND_GET_INSTANCE_METHOD.get(
+              className, String.valueOf(e.getMessage()));
+          throw new InitializationException(msg, e);
+        }
+
+        // Get the definition instance.
+        AbstractManagedObjectDefinition<?, ?> d;
+        try {
+          d = (AbstractManagedObjectDefinition<?, ?>) method.invoke(null);
+        } catch (Exception e) {
+          Message msg = ERR_CLASS_LOADER_CANNOT_INVOKE_GET_INSTANCE_METHOD.get(
+              className, String.valueOf(e.getMessage()));
+          throw new InitializationException(msg, e);
+        }
+        definitions.add(d);
+      }
+    }
+
+    // Initialize any definitions that were loaded.
+    for (AbstractManagedObjectDefinition<?, ?> d : definitions) {
+      try {
+        d.initialize();
+      } catch (Exception e) {
+        Message msg = ERR_CLASS_LOADER_CANNOT_INITIALIZE_DEFN.get(d.getName(),
+            d.getClass().getName(), String.valueOf(e.getMessage()));
+        throw new InitializationException(msg, e);
+      }
     }
   }
 

--
Gitblit v1.10.0