From 95df5cfdba474acb03076953e992b898fbb277a8 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 02 Feb 2009 23:37:54 +0000
Subject: [PATCH] Fix issue 3734 - Make network group policies extensible.

---
 opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java |  292 ++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 160 insertions(+), 132 deletions(-)

diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
index b9a23c2..c2281d2 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -35,13 +35,14 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TreeMap;
 import java.util.TreeSet;
 
 import org.opends.messages.Message;
@@ -66,6 +67,7 @@
 import org.opends.server.admin.PropertyOption;
 import org.opends.server.admin.PropertyProvider;
 import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SetRelationDefinition;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.CommunicationException;
 import org.opends.server.admin.client.ConcurrentModificationException;
@@ -397,6 +399,33 @@
 
 
   /**
+   * Creates a new create-xxx sub-command for a sets
+   * relation.
+   *
+   * @param <C>
+   *          The type of managed object which can be created.
+   * @param <S>
+   *          The type of server managed object which can be created.
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The set relation.
+   * @return Returns the new create-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static <C extends ConfigurationClient, S extends Configuration>
+      CreateSubCommandHandler<C, S> create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
+      SetRelationDefinition<C, S> r) throws ArgumentException {
+    return new CreateSubCommandHandler<C, S>(parser, p, r, null, p.child(r));
+  }
+
+
+
+  /**
    * Creates a new create-xxx sub-command for an optional relation.
    *
    * @param <C>
@@ -499,7 +528,7 @@
 
     // First determine what type of component the user wants to create.
     MenuResult<ManagedObjectDefinition<? extends C, ? extends S>> result;
-    result = getTypeInteractively(app, d);
+    result = getTypeInteractively(app, d, Collections.<String>emptySet());
 
     ManagedObjectDefinition<? extends C, ? extends S> mod;
     if (result.isSuccess()) {
@@ -913,78 +942,56 @@
 
 
 
-  // Generate the type name - definition mapping table.
-  @SuppressWarnings("unchecked")
-  private static <C extends ConfigurationClient, S extends Configuration>
-  SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>>
-      getSubTypes(AbstractManagedObjectDefinition<C, S> d) {
-    SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>> map;
-    map =
-      new TreeMap<String, ManagedObjectDefinition<? extends C, ? extends S>>();
-
-    // If the top-level definition is instantiable, we use the value
-    // "generic" or "custom".
-    if (!d.hasOption(ManagedObjectOption.HIDDEN)) {
-      if (d instanceof ManagedObjectDefinition) {
-        ManagedObjectDefinition<? extends C, ? extends S> mod =
-          (ManagedObjectDefinition<? extends C, ? extends S>) d;
-        if (CLIProfile.getInstance().isForCustomization(mod)) {
-          map.put(DSConfig.CUSTOM_TYPE, mod);
-        } else {
-          map.put(DSConfig.GENERIC_TYPE, mod);
-        }
-      }
-    }
-
-    // Process its sub-definitions.
-    String suffix = "-" + d.getName();
-    for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
-        .getAllChildren()) {
-      if (d.hasOption(ManagedObjectOption.HIDDEN)) {
-        continue;
-      }
-
-      if (c instanceof ManagedObjectDefinition) {
-        ManagedObjectDefinition<? extends C, ? extends S> mod =
-          (ManagedObjectDefinition<? extends C, ? extends S>) c;
-
-        // For the type name we shorten it, if possible, by stripping
-        // off the trailing part of the name which matches the
-        // base-type.
-        String name = mod.getName();
-        if (name.endsWith(suffix)) {
-          name = name.substring(0, name.length() - suffix.length());
-        }
-
-        // If this type is intended for customization, prefix it with
-        // "custom".
-        if (CLIProfile.getInstance().isForCustomization(mod)) {
-          name = String.format("%s-%s", DSConfig.CUSTOM_TYPE, name);
-        }
-
-        map.put(name, mod);
-      }
-    }
-
-    return map;
-  }
-
-
-
   // Interactively ask the user which type of component they want to create.
   private static <C extends ConfigurationClient, S extends Configuration>
       MenuResult<ManagedObjectDefinition<? extends C, ? extends S>>
       getTypeInteractively(ConsoleApplication app,
-          AbstractManagedObjectDefinition<C, S> d) throws CLIException {
-    Collection<ManagedObjectDefinition<? extends C, ? extends S>> types;
-    types = getSubTypes(d).values();
+          AbstractManagedObjectDefinition<C, S> d,
+          Set<String> prohibitedTypes) throws CLIException {
+    // First get the list of available of sub-types.
+    List<ManagedObjectDefinition<? extends C, ? extends S>> filteredTypes =
+      new LinkedList<ManagedObjectDefinition<? extends C,? extends S>>(
+          getSubTypes(d).values());
+    boolean isOnlyOneType = filteredTypes.size() == 1;
+
+    Iterator<ManagedObjectDefinition<? extends C,? extends S>> i;
+    for (i = filteredTypes.iterator() ; i.hasNext();) {
+      ManagedObjectDefinition<? extends C,? extends S> cd = i.next();
+
+      if (prohibitedTypes.contains(cd.getName())) {
+        // Remove filtered types.
+        i.remove();
+      } else if (!app.isAdvancedMode()) {
+        // Only display advanced types and custom types in advanced mode.
+        if (cd.hasOption(ManagedObjectOption.ADVANCED)) {
+          i.remove();
+        } else if (CLIProfile.getInstance().isForCustomization(cd)) {
+          i.remove();
+        }
+      }
+    }
 
     // If there is only one choice then return immediately.
-    if (types.size() == 1) {
-      ManagedObjectDefinition<? extends C, ? extends S> type =
-        types.iterator().next();
+    if (filteredTypes.size() == 0) {
+      Message msg =
+        ERR_DSCFG_ERROR_NO_AVAILABLE_TYPES.get(d.getUserFriendlyName());
+      app.println(msg);
       return MenuResult.<ManagedObjectDefinition<? extends C,
-          ? extends S>>success(type);
+          ? extends S>>cancel();
+    } else if (filteredTypes.size() == 1) {
+      ManagedObjectDefinition<? extends C, ? extends S> type =
+        filteredTypes.iterator().next();
+      if (!isOnlyOneType) {
+        // Only one option available so confirm that the user wishes to
+        // use it.
+        Message msg = INFO_DSCFG_TYPE_PROMPT_SINGLE.get(
+            d.getUserFriendlyName(), type.getUserFriendlyName());
+        if (!app.confirmAction(msg, true)) {
+          return MenuResult.cancel();
+        }
+      }
+      return MenuResult.<ManagedObjectDefinition<? extends C, ? extends S>>
+        success(type);
     } else {
       MenuBuilder<ManagedObjectDefinition<? extends C, ? extends S>> builder =
         new MenuBuilder<ManagedObjectDefinition<? extends C, ? extends S>>(app);
@@ -992,17 +999,8 @@
       builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
       builder.setPrompt(msg);
 
-      for (ManagedObjectDefinition<? extends C, ? extends S> mod : types) {
-        // Only display advanced types and custom types in advanced mode.
-        if (!app.isAdvancedMode()) {
-          if (mod.hasOption(ManagedObjectOption.ADVANCED)) {
-            continue;
-          }
-
-          if (CLIProfile.getInstance().isForCustomization(mod)) {
-            continue;
-          }
-        }
+      for (ManagedObjectDefinition<? extends C, ? extends S> mod :
+        filteredTypes) {
 
         Message option = mod.getUserFriendlyName();
         if (CLIProfile.getInstance().isForCustomization(mod)) {
@@ -1083,6 +1081,9 @@
     // Create the naming arguments.
     this.namingArgs = createNamingArgs(subCommand, c, true);
 
+    // Build the -t option usage.
+    this.typeUsage = getSubTypesUsage(r.getChildDefinition());
+
     // Create the --property argument which is used to specify
     // property values.
     this.propertySetArgument = new StringArgument(OPTION_DSCFG_LONG_SET,
@@ -1091,18 +1092,6 @@
         INFO_DSCFG_DESCRIPTION_PROP_VAL.get());
     this.subCommand.addArgument(this.propertySetArgument);
 
-    // Build the -t option usage.
-    StringBuilder builder = new StringBuilder();
-    boolean isFirst = true;
-    for (String s : types.keySet()) {
-      if (!isFirst) {
-        builder.append(" | ");
-      }
-      builder.append(s);
-      isFirst = false;
-    }
-    this.typeUsage = builder.toString();
-
     if (!types.containsKey(DSConfig.GENERIC_TYPE)) {
       // The option is mandatory when non-interactive.
       this.typeArgument = new StringArgument("type", OPTION_DSCFG_SHORT_TYPE,
@@ -1163,43 +1152,7 @@
   public MenuResult<Integer> run(ConsoleApplication app,
       ManagementContextFactory factory) throws ArgumentException,
       ClientException, CLIException {
-    // Determine the type of managed object to be created.
-    ManagedObjectDefinition<? extends C, ? extends S> d;
-    if (!typeArgument.isPresent()) {
-      if (app.isInteractive()) {
-        // Let the user choose.
-        MenuResult<ManagedObjectDefinition<? extends C, ? extends S>> result;
-        app.println();
-        app.println();
-        result = getTypeInteractively(app, relation.getChildDefinition());
-
-        if (result.isSuccess()) {
-          d = result.getValue();
-        } else if (result.isCancel()) {
-          return MenuResult.cancel();
-        } else {
-          // Must be quit.
-          if (!app.isMenuDrivenMode()) {
-            app.printVerboseMessage(INFO_DSCFG_CONFIRM_CREATE_FAIL.get(relation
-                .getUserFriendlyName()));
-          }
-          return MenuResult.quit();
-        }
-      } else if (typeArgument.getDefaultValue() != null) {
-        d = types.get(typeArgument.getDefaultValue());
-      } else {
-        throw ArgumentExceptionFactory
-            .missingMandatoryNonInteractiveArgument(typeArgument);
-      }
-    } else {
-      d = types.get(typeArgument.getValue());
-      if (d == null) {
-        throw ArgumentExceptionFactory.unknownSubType(relation, typeArgument
-            .getValue(), typeUsage);
-      }
-    }
-
-    Message ufn = d.getUserFriendlyName();
+    Message ufn = relation.getUserFriendlyName();
 
     // Get the naming argument values.
     List<String> names = getNamingArgValues(app, namingArgs);
@@ -1212,11 +1165,6 @@
     // Update the command builder.
     updateCommandBuilderWithSubCommand();
 
-    // Encode the provided properties.
-    List<String> propertyArgs = propertySetArgument.getValues();
-    MyPropertyProvider provider = new MyPropertyProvider(d,
-        namingPropertyDefinition, propertyArgs);
-
     // Add the child managed object.
     ManagementContext context = factory.getManagementContext(app);
     MenuResult<ManagedObject<?>> result;
@@ -1265,6 +1213,82 @@
     }
 
     ManagedObject<?> parent = result.getValue();
+
+    // Determine the type of managed object to be created. If we are creating
+    // a managed object beneath a set relation then prevent creation of
+    // duplicates.
+    Set<String> prohibitedTypes;
+    if (relation instanceof SetRelationDefinition) {
+      SetRelationDefinition<C, S> sr = (SetRelationDefinition<C, S>) relation;
+      prohibitedTypes = new HashSet<String>();
+      try
+      {
+        for (String child : parent.listChildren(sr)) {
+          prohibitedTypes.add(child);
+        }
+      }
+      catch (AuthorizationException e)
+      {
+        Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(ufn);
+        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+            msg);
+      }
+      catch (ConcurrentModificationException e)
+      {
+        Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(ufn);
+        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
+      }
+      catch (CommunicationException e)
+      {
+        Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(ufn, e
+            .getMessage());
+        throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
+      }
+    } else {
+      // No prohibited types.
+      prohibitedTypes = Collections.emptySet();
+    }
+
+    ManagedObjectDefinition<? extends C, ? extends S> d;
+    if (!typeArgument.isPresent()) {
+      if (app.isInteractive()) {
+        // Let the user choose.
+        MenuResult<ManagedObjectDefinition<? extends C, ? extends S>> dresult;
+        app.println();
+        app.println();
+        dresult = getTypeInteractively(app, relation.getChildDefinition(),
+            prohibitedTypes);
+
+        if (dresult.isSuccess()) {
+          d = dresult.getValue();
+        } else if (dresult.isCancel()) {
+          return MenuResult.cancel();
+        } else {
+          // Must be quit.
+          if (!app.isMenuDrivenMode()) {
+            app.printVerboseMessage(INFO_DSCFG_CONFIRM_CREATE_FAIL.get(ufn));
+          }
+          return MenuResult.quit();
+        }
+      } else if (typeArgument.getDefaultValue() != null) {
+        d = types.get(typeArgument.getDefaultValue());
+      } else {
+        throw ArgumentExceptionFactory
+            .missingMandatoryNonInteractiveArgument(typeArgument);
+      }
+    } else {
+      d = types.get(typeArgument.getValue());
+      if (d == null) {
+        throw ArgumentExceptionFactory.unknownSubType(relation, typeArgument
+            .getValue(), typeUsage);
+      }
+    }
+
+    // Encode the provided properties.
+    List<String> propertyArgs = propertySetArgument.getValues();
+    MyPropertyProvider provider = new MyPropertyProvider(d,
+        namingPropertyDefinition, propertyArgs);
+
     ManagedObject<? extends C> child;
     List<DefaultBehaviorException> exceptions =
       new LinkedList<DefaultBehaviorException>();
@@ -1297,6 +1321,10 @@
               .adaptIllegalManagedObjectNameException(e, d);
         }
       }
+    } else if (relation instanceof SetRelationDefinition) {
+      SetRelationDefinition<C, S> srelation =
+        (SetRelationDefinition<C, S>) relation;
+      child = parent.createChild(srelation, d, exceptions);
     } else {
       OptionalRelationDefinition<C, S> orelation =
         (OptionalRelationDefinition<C, S>) relation;

--
Gitblit v1.10.0