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

lutoff
31.31.2007 df0a5c41f5f842f72916027b70cbae7359b34508
Commit related to issue 
https://opends.dev.java.net/issues/show_bug.cgi?id=1334

This commit implements the underlying actions for the following subcommand:

add-to-group Add a member to a group
create-group Create a new group of servers
delete-group Delete an existing new group of servers
list-groups List groups that have been defined
list-members List members of the specified group
list-membership List members of the specified group
modify-group Modify a group's properties
remove-from-group Remove a member from a group

Error handling and user friendly outputs are not part of this commit.
1 files deleted
5 files added
5 files modified
2145 ■■■■ changed files
opends/src/ads/org/opends/admin/ads/ADSContext.java 345 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/ADSContextException.java 2 ●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/ADSContextHelper.java 11 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/DsServiceCLI.java 323 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/DsServiceCliAds.java 179 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/DsServiceCliMain.java 242 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/DsServiceCliParser.java 334 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/DsServiceCliServerGroup.java 587 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/DsServiceCliSubCommandGroup.java 85 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/AdminMessages.java 31 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ToolConstants.java 6 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/ADSContext.java
@@ -27,11 +27,6 @@
package org.opends.admin.ads;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Set;
import java.util.HashSet;
@@ -186,7 +181,7 @@
    /**
     * The members of the server group.
     */
    MEMBERS("members");
    MEMBERS("uniqueMember");
    private String attrName;
@@ -445,11 +440,80 @@
    return result;
  }
  /**
   * Returns the member list of a group of server.
   *
   * @param serverGroupId
   *          The group name.
   * @return the member list of a group of server.
   * @throws ADSContextException
   *           if something goes wrong.
   */
  public Set<String> getServerGroupMemberList(
      String serverGroupId) throws ADSContextException
  {
    LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + ","
        + getServerGroupContainerDN());
    Set<String> result = new HashSet<String>() ;
    try
    {
      SearchControls sc = new SearchControls();
      sc.setSearchScope(SearchControls.OBJECT_SCOPE);
      NamingEnumeration<SearchResult> srs = getDirContext().search(dn,
          "(objectclass=*)", sc);
      if (!srs.hasMore())
      {
        return result;
      }
      Attributes attrs = srs.next().getAttributes();
      NamingEnumeration ne = attrs.getAll();
      while (ne.hasMore())
      {
        Attribute attr = (Attribute)ne.next();
        String attrID = attr.getID();
        if (!attrID.toLowerCase().equals(
            ServerGroupProperty.MEMBERS.getAttributeName().toLowerCase()))
        {
          continue;
        }
        // We have the members list
        NamingEnumeration ae = attr.getAll();
        while (ae.hasMore())
        {
          result.add((String)ae.next());
        }
        break;
      }
    }
    catch (NameNotFoundException x)
    {
      result = new HashSet<String>();
    }
    catch (NoPermissionException x)
    {
      throw new ADSContextException(
          ADSContextException.ErrorType.ACCESS_PERMISSION);
    }
    catch (NamingException x)
    {
      throw new ADSContextException(
          ADSContextException.ErrorType.ERROR_UNEXPECTED, x);
    }
    return result;
  }
  /**
   * Returns a set containing the servers that are registered in the ADS.
   * @return a set containing the servers that are registered in the ADS.
   * @throws ADSContextException if something goes wrong.
   * Returns a set containing the servers that are registered in the
   * ADS.
   *
   * @return a set containing the servers that are registered in the
   *         ADS.
   * @throws ADSContextException
   *           if something goes wrong.
   */
  public Set<Map<ServerProperty,Object>> readServerRegistry()
  throws ADSContextException
@@ -583,6 +647,9 @@
    LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties);
    BasicAttributes attrs = makeAttrsFromServerGroupProperties(
        serverGroupProperties);
    // Add the objectclass attribute value
    attrs.put("objectclass", "top");
    attrs.put("objectclass", "groupOfUniqueNames");
    try
    {
      DirContext ctx = dirContext.createSubcontext(dn, attrs);
@@ -604,13 +671,16 @@
   * Updates the properties of a Server Group in the ADS.
   * @param serverGroupProperties the new properties of the server group to be
   * updated.
   * @param groupID The group name.
   * @throws ADSContextException if somethings goes wrong.
   */
  public void updateServerGroup(
  public void updateServerGroup(String groupID,
      Map<ServerGroupProperty, Object> serverGroupProperties)
  throws ADSContextException
  {
    LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties);
    LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," +
        getServerGroupContainerDN());
    BasicAttributes attrs =
      makeAttrsFromServerGroupProperties(serverGroupProperties);
    try
@@ -630,6 +700,38 @@
  }
  /**
   * Updates the properties of a Server Group in the ADS.
   * @param serverGroupProperties the new properties of the server group to be
   * updated.
   * @param groupID The group name.
   * @throws ADSContextException if somethings goes wrong.
   */
  public void removeServerGroupProp(String groupID,
      Set<ServerGroupProperty> serverGroupProperties)
  throws ADSContextException
  {
    LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," +
        getServerGroupContainerDN());
    BasicAttributes attrs =
      makeAttrsFromServerGroupProperties(serverGroupProperties);
    try
    {
      dirContext.modifyAttributes(dn, DirContext.REMOVE_ATTRIBUTE, attrs);
    }
    catch (NameAlreadyBoundException x)
    {
      throw new ADSContextException(
          ADSContextException.ErrorType.ALREADY_REGISTERED);
    }
    catch (NamingException x)
    {
      throw new ADSContextException(
          ADSContextException.ErrorType.ERROR_UNEXPECTED, x);
    }
  }
  /**
   * Deletes a Server Group in the ADS.
   * @param serverGroupProperties the properties of the server group to be
   * deleted.
@@ -762,134 +864,6 @@
    createContainerEntry(getServerGroupContainerDN());
  }
  /**
   * TODO: remove this method if we can assume that the server during setup
   * can be started to do a number of things.
   * NOTE: this can only be called locally.
   * The call to this method assumes that OpenDS.jar has already been loaded.
   * So this should not be called by the Java Web Start before being sure that
   * this jar is loaded.
   * @param serverProperties the properties of the servers to register.
   * @param serverGroupProperties the properties of the server groups to
   * register.
   * @param administratorProperties the properties of the administrators to
   * register.
   * @param installPath the installation path of the server.
   * @throws ADSContextException if something goes wrong.
   */
  public static void createOfflineAdminData(
      Set<Map<ServerProperty, Object>> serverProperties,
      Set<Map<ServerGroupProperty, Object>> serverGroupProperties,
      Set<Map<AdministratorProperty, Object>> administratorProperties,
      String installPath)
  throws ADSContextException
  {
    // Add the administration suffix
    createOfflineAdministrationSuffix(installPath);
    // Create the DIT below the administration suffix
    try
    {
      File ldifFile = File.createTempFile("ads", ".ldif");
      ldifFile.deleteOnExit();
      LinkedList<String> lines = new LinkedList<String>();
      lines.add("dn: "+getAdministrationSuffixDN());
      lines.add("objectclass: extensibleobject");
      lines.add("aci: "+getTopContainerACI());
      lines.add("");
      lines.add("dn: "+getAdministratorContainerDN());
      lines.add("objectclass: groupOfUniqueNames");
      lines.add("objectclass: groupofurls");
      lines.add("memberURL: ldap:///" + getAdministratorContainerDN() +
      "??one?(objectclass=*)");
      lines.add("description: Group of identities which have full access.");
      lines.add("dn: "+getServerContainerDN());
      lines.add("objectclass: extensibleobject");
      lines.add("");
      lines.add("dn: "+getServerGroupContainerDN());
      lines.add("objectclass: extensibleobject");
      for (Map<ServerProperty, Object> props : serverProperties)
      {
        lines.add("");
        LdapName dn = makeDNFromServerProperties(props);
        BasicAttributes attrs = makeAttrsFromServerProperties(props);
        addToLines(dn, attrs, lines);
      }
      for (Map<ServerGroupProperty, Object> props : serverGroupProperties)
      {
        lines.add("");
        LdapName dn = makeDNFromServerGroupProperties(props);
        BasicAttributes attrs = makeAttrsFromServerGroupProperties(props);
        addToLines(dn, attrs, lines);
      }
      for (Map<AdministratorProperty, Object> props : administratorProperties)
      {
        lines.add("");
        LdapName dn = makeDNFromAdministratorProperties(props);
        BasicAttributes attrs = makeAttrsFromAdministratorProperties(props);
        addToLines(dn, attrs, lines);
      }
      BufferedWriter writer = new BufferedWriter(new FileWriter(ldifFile));
      for (String line : lines)
      {
        writer.write(line);
        writer.newLine();
      }
      writer.flush();
      writer.close();
      ArrayList<String> argList = new ArrayList<String>();
      argList.add("-C");
      argList.add(
          org.opends.server.extensions.ConfigFileHandler.class.getName());
      argList.add("-c");
      argList.add(installPath+File.separator+"config"+File.separator+
          "config.ldif");
      argList.add("-n");
      argList.add(getBackendName());
      argList.add("-t");
      argList.add(ldifFile.getAbsolutePath());
      argList.add("-S");
      argList.add("0");
      String[] args = new String[argList.size()];
      argList.toArray(args);
      try
      {
        int result = org.opends.server.tools.ImportLDIF.mainImportLDIF(args);
        if (result != 0)
        {
          throw new ADSContextException(
              ADSContextException.ErrorType.ERROR_UNEXPECTED);
        }
      } catch (Throwable t)
      {
//      This should not happen
        throw new ADSContextException(
            ADSContextException.ErrorType.ERROR_UNEXPECTED, t);
      }
    }
    catch (IOException ioe)
    {
//    This should not happen
      throw new ADSContextException(
          ADSContextException.ErrorType.ERROR_UNEXPECTED, ioe);
    }
  }
  /**
   * Removes the administration data.
@@ -1297,8 +1271,29 @@
        result.put(attr);
      }
    }
    // Add the objectclass attribute value
    result.put("objectclass", "extensibleobject");
    return result;
  }
  /**
   * Returns the attributes for some server group properties.
   * @param serverProperties the server group properties.
   * @return the attributes for the given server group properties.
   * @throws ADSContextException if something goes wrong.
   */
  private static BasicAttributes makeAttrsFromServerGroupProperties(
      Set<ServerGroupProperty> serverGroupProperties)
  {
    BasicAttributes result = new BasicAttributes();
    // Transform 'properties' into 'attributes'
    for (ServerGroupProperty prop: serverGroupProperties)
    {
      Attribute attr = makeAttrFromServerGroupProperty(prop,null);
      if (attr != null)
      {
        result.put(attr);
      }
    }
    return result;
  }
@@ -1344,29 +1339,15 @@
      new HashMap<ServerGroupProperty, Object>();
    try
    {
      NamingEnumeration ne = attrs.getAll();
      while (ne.hasMore())
      for (ServerGroupProperty prop : ServerGroupProperty.values())
      {
        Attribute attr = (Attribute)ne.next();
        String attrID = attr.getID();
        Attribute attr = (Attribute) attrs.get(prop.getAttributeName());
        if (attr == null)
        {
          continue ;
        }
        Object value = null;
        ServerGroupProperty prop = null;
        ServerGroupProperty[] props = ServerGroupProperty.values();
        for (int i=0; i<props.length && (prop == null); i++)
        {
          String v = props[i].getAttributeName();
          if (attrID.equalsIgnoreCase(v))
          {
            prop = props[i];
          }
        }
        if (prop == null)
        {
          throw new ADSContextException(
              ADSContextException.ErrorType.ERROR_UNEXPECTED);
        }
        if (attr.size() >= 1 &&
            MULTIVALUED_SERVER_GROUP_PROPERTIES.contains(prop))
        {
@@ -1769,7 +1750,9 @@
  {
    BasicAttributes attrs = new BasicAttributes();
    attrs.put("objectclass", "extensibleobject");
    attrs.put("objectclass", "top");
    attrs.put("objectclass", "ds-cfg-branch");
    // attrs.put("objectclass", "extensibleobject");
    createEntry(dn, attrs);
  }
@@ -1798,7 +1781,8 @@
  {
    BasicAttributes attrs = new BasicAttributes();
    attrs.put("objectclass", "extensibleobject");
    attrs.put("objectclass", "top");
    attrs.put("objectclass", "ds-cfg-branch");
    attrs.put("aci", getTopContainerACI());
    createEntry(getAdministrationSuffixDN(), attrs);
  }
@@ -1851,41 +1835,6 @@
  }
  /**
   * Creates the Administration Suffix when the server is down.  This can only
   * be called locally.
   * @param installPath the installation path of the server
   * @throws ADSContextException if something goes wrong.
   */
  private static void createOfflineAdministrationSuffix(String installPath)
  throws ADSContextException
  {
    // NOTE: the call to this method assumes
    // that OpenDS.jar has already been loaded.  So this should not be called by
    // the Java Web Start before being sure that this jar is loaded.
    ArrayList<String> argList = new ArrayList<String>();
    argList.add("-C");
    argList.add(org.opends.server.extensions.ConfigFileHandler.class.getName());
    argList.add("-c");
    argList.add(installPath+File.separator+"config"+File.separator+
        "config.ldif");
    argList.add("-b");
    argList.add(getAdministrationSuffixDN());
    String[] args = new String[argList.size()];
    argList.toArray(args);
    int returnValue = org.opends.server.tools.ConfigureDS.configMain(args);
    if (returnValue != 0)
    {
      throw new ADSContextException(
          ADSContextException.ErrorType.ERROR_UNEXPECTED);
    }
  }
  /**
   * Removes the administration suffix.
   * @throws ADSContextException
   */
opends/src/ads/org/opends/admin/ads/ADSContextException.java
@@ -151,7 +151,7 @@
  {
    if (toString == null)
    {
      toString = "ADSContextException: error type"+error+".";
      toString = "ADSContextException: error type "+error+".";
      if (getCause() != null)
      {
        toString += "  Root cause: "+getCause().toString();
opends/src/ads/org/opends/admin/ads/ADSContextHelper.java
@@ -32,6 +32,7 @@
import javax.naming.ldap.InitialLdapContext;
import org.opends.server.admin.ManagedObjectNotFoundException;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
import org.opends.server.admin.client.ldap.LDAPManagementContext;
@@ -72,7 +73,15 @@
      ManagementContext mCtx = LDAPManagementContext.createFromContext(
          JNDIDirContextAdaptor.adapt(ctx));
      RootCfgClient root = mCtx.getRootConfiguration();
      BackendCfgClient backend = root.getBackend(backendName);
      BackendCfgClient backend = null;
      try
      {
        backend = root.getBackend(backendName);
      }
      catch (ManagedObjectNotFoundException monfe)
      {
        // It does not exist.
      }
      if (backend != null)
      {
        SortedSet<DN> suffixes = backend.getBackendBaseDN();
opends/src/ads/org/opends/admin/ads/DsServiceCLI.java
File was deleted
opends/src/ads/org/opends/admin/ads/DsServiceCliAds.java
New file
@@ -0,0 +1,179 @@
/*
 * 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 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.admin.ads;
import static org.opends.server.messages.AdminMessages.*;
import static org.opends.server.tools.ToolConstants.*;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
/**
 * This class is handling server group CLI.
 */
public class DsServiceCliAds implements DsServiceCliSubCommandGroup
{
  /**
   * The subcommand Parser.
   */
  SubCommandArgumentParser argParser ;
  /**
   * The verbose argument.
   */
  BooleanArgument verboseArg ;
  /**
   * The enumeration containing the different subCommand names.
   */
  private enum SubCommandNameEnum
  {
    /**
     * The create-ads subcommand.
     */
    CREATE_ADS("create-ads"),
    /**
     * The delete-ads subcommand.
     */
    DELETE_ADS("delete-ads");
    // String representation of the value.
    private final String name;
    // Private constructor.
    private SubCommandNameEnum(String name)
    {
      this.name = name;
    }
    /**
     * {@inheritDoc}
     */
    public String toString()
    {
      return name;
    }
    // A lookup table for resolving a unit from its name.
    private static final List<String> nameToSubCmdName ;
    static
    {
      nameToSubCmdName = new ArrayList<String>();
      for (SubCommandNameEnum subCmd : SubCommandNameEnum.values())
      {
        nameToSubCmdName.add(subCmd.toString());
      }
    }
    public static boolean  isSubCommand(String name)
    {
      return nameToSubCmdName.contains(name);
    }
  }
  /**
   * The 'create-ads' subcommand.
   */
  public SubCommand createAdsSubCmd;
  /**
   * The 'delete-ads' subcommand.
   */
  private SubCommand deleteAdsSubCmd;
  /**
   * {@inheritDoc}
   */
  public void initializeCliGroup(SubCommandArgumentParser argParser,
      BooleanArgument verboseArg)
      throws ArgumentException
  {
    this.argParser = argParser ;
    this.verboseArg = verboseArg ;
    // Create-ads subcommand
    createAdsSubCmd = new SubCommand(argParser, SubCommandNameEnum.CREATE_ADS
        .toString(), true, 1, 1, OPERAND_BACKEND,
        MSGID_DSSERVICE_SUBCMD_CREATE_ADS_DESCRIPTION);
    createAdsSubCmd.setHidden(true);
    // delete-ads
    deleteAdsSubCmd = new SubCommand(argParser,SubCommandNameEnum.DELETE_ADS
        .toString(), true, 1, 1, OPERAND_BACKEND,
        MSGID_DSSERVICE_SUBCMD_DELETE_ADS_DESCRIPTION);
    deleteAdsSubCmd.setHidden(true);
  }
  /**
   * {@inheritDoc}
   */
  public boolean isSubCommand(SubCommand subCmd)
  {
      return SubCommandNameEnum.isSubCommand(subCmd.getName());
  }
  /**
   * {@inheritDoc}
   */
  public int performSubCommand(ADSContext adsContext, SubCommand subCmd,
      OutputStream outStream, OutputStream errStream)
      throws ADSContextException
  {
    //
    // create-ads subcommand
    if (subCmd.getName().equals(createAdsSubCmd.getName()))
    {
      String backendName = subCmd.getTrailingArguments().get(0);
      ADSContextHelper helper = new ADSContextHelper();
      adsContext.createAdminData();
      helper.createAdministrationSuffix(adsContext.getDirContext(),
          backendName);
      return 0;
    }
    else if (subCmd.getName().equals(deleteAdsSubCmd.getName()))
    {
      String backendName = subCmd.getTrailingArguments().get(0);
      ADSContextHelper helper = new ADSContextHelper();
      helper.removeAdministrationSuffix(adsContext.getDirContext(),
          backendName);
      return 0;
    }
    // Should never occurs: If we are here, it means that the code to
    // handle to subcommand is not yet written.
    return 1;
  }
}
opends/src/ads/org/opends/admin/ads/DsServiceCliMain.java
New file
@@ -0,0 +1,242 @@
/*
 * 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 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.admin.ads;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.args.ArgumentException;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.AdminMessages.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class provides a tool that can be used to Directory Server services.
 */
public class DsServiceCliMain
{
  /**
   * The fully-qualified name of this class.
   */
  private static final String CLASS_NAME =
      "org.opends.admin.ads.DsServiceCLI";
  // The print stream to use for standard error.
  private PrintStream err;
  // The print stream to use for standard output.
  private PrintStream out;
  /**
   * Constructor for the DsServiceCLI object.
   *
   * @param  out            The print stream to use for standard output.
   * @param  err            The print stream to use for standard error.
   */
  public DsServiceCliMain(PrintStream out, PrintStream err)
  {
    this.out           = out;
    this.err           = err;
  }
  /**
   * The main method for dsservice tool.
   *
   * @param  args  The command-line arguments provided to this program.
   */
  public static void main(String[] args)
  {
    int retCode = mainCLI(args, System.out, System.err);
    if(retCode != 0)
    {
      System.exit(retCode);
    }
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the dsservice tool.
   *
   * @param  args  The command-line arguments provided to this program.
   *
   * @return The error code.
   */
  public static int mainCLI(String[] args)
  {
    return mainCLI(args, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the dsservice tool.
   *
   * @param  args              The command-line arguments provided to this
   *                           program.
   * @param  outStream         The output stream to use for standard output, or
   *                           <CODE>null</CODE> if standard output is not
   *                           needed.
   * @param  errStream         The output stream to use for standard error, or
   *                           <CODE>null</CODE> if standard error is not
   *                           needed.
   *
   * @return The error code.
   */
  public static int mainCLI(String[] args, OutputStream outStream,
      OutputStream errStream)
  {
    PrintStream out;
    if (outStream == null)
    {
      out = NullOutputStream.printStream();
    }
    else
    {
      out = new PrintStream(outStream);
    }
    PrintStream err;
    if (errStream == null)
    {
      err = NullOutputStream.printStream();
    }
    else
    {
      err = new PrintStream(errStream);
    }
    // Create the command-line argument parser for use with this
    // program.
    DsServiceCliParser argParser ;
    try
    {
      String toolDescription = getMessage(MSGID_DSSERVICE_TOOL_DESCRIPTION);
      argParser = new DsServiceCliParser(CLASS_NAME,
          toolDescription, false);
      argParser.initializeParser(out);
    }
    catch (ArgumentException ae)
    {
      int msgID = MSGID_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    // Parse the command-line arguments provided to this program.
    try
    {
      argParser.parseArguments(args);
    }
    catch (ArgumentException ae)
    {
      int    msgID   = MSGID_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      err.println(argParser.getUsage());
      return 1;
    }
    // If we should just display usage information, then print it and exit.
    if (argParser.usageOrVersionDisplayed())
    {
      return 0;
    }
    // Get connection parameters
    String host = argParser.getHostName() ;
    String port = argParser.getPort() ;
    String dn   = argParser.getBindDN() ;
    String pwd  = argParser.getBindPassword(dn,out,err) ;
    if (pwd == null)
    {
      // TODO Should we do something?
      return 1;
    }
    // Try to connect
    String ldapUrl = "ldap://"+host+":"+port;
   InitialLdapContext ctx = null;
   int returnCode = 0 ;
    try
    {
      ctx = ConnectionUtils.createLdapContext(ldapUrl, dn, pwd,
          ConnectionUtils.getDefaultLDAPTimeout(), null);
    }
    catch (NamingException e)
    {
      int    msgID   = MSGID_DSSERVICE_CANNOT_CONNECT_TO_ADS;
      String message = getMessage(msgID, host);
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    ADSContext adsContext = new ADSContext(ctx);
    DirectoryServer.bootstrapClient();
    // perform the subCommand
    try
    {
      returnCode = argParser.performSubCommand(adsContext, out, err);
    }
    catch (ADSContextException e)
    {
      // TODO Print a nice message
      e.printStackTrace();
      returnCode = e.error.ordinal();
    }
    // deconnection
    try
    {
      ctx.close();
    }
    catch (NamingException e)
    {
      // TODO Should we do something ?
    }
    return returnCode;
  }
}
opends/src/ads/org/opends/admin/ads/DsServiceCliParser.java
New file
@@ -0,0 +1,334 @@
/*
 * 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 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.admin.ads;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.tools.ToolConstants.*;
import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
import static org.opends.server.util.StaticUtils.wrapText;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.HashSet;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.util.PasswordReader;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.FileBasedArgument;
import org.opends.server.util.args.IntegerArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
/**
 * This class will parser CLI arguments.
 */
public class DsServiceCliParser extends SubCommandArgumentParser
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  /**
   * The showUsage' global argument.
   */
  private BooleanArgument showUsageArg = null;
  /**
   * The 'useSSLArg' global argument.
   */
  private BooleanArgument useSSLArg = null;
  /**
   * The 'hostName' global argument.
   */
  private StringArgument hostNameArg = null;
  /**
   * The 'port' global argument.
   */
  private IntegerArgument portArg = null;
  /**
   * The 'binDN' global argument.
   */
  private StringArgument bindDnArg = null;
  /**
   * The 'bindPasswordFile' global argument.
   */
  private FileBasedArgument bindPasswordFileArg = null;
  /**
   * The 'verbose' global argument.
   */
  private BooleanArgument verboseArg = null;
  /**
   * The diferent CLI group.
   */
  public HashSet<DsServiceCliSubCommandGroup> cliGroup;
  /**
   * Creates a new instance of this subcommand argument parser with no
   * arguments.
   *
   * @param mainClassName
   *          The fully-qualified name of the Java class that should
   *          be invoked to launch the program with which this
   *          argument parser is associated.
   * @param toolDescription
   *          A human-readable description for the tool, which will be
   *          included when displaying usage information.
   * @param longArgumentsCaseSensitive
   *          Indicates whether subcommand and long argument names
   *          should be treated in a case-sensitive manner.
   */
  public DsServiceCliParser(String mainClassName, String toolDescription,
      boolean longArgumentsCaseSensitive)
  {
    super(mainClassName, toolDescription, longArgumentsCaseSensitive);
    cliGroup = new HashSet<DsServiceCliSubCommandGroup>();
  }
  /**
   * Initialize the parser with the Gloabal options ans subcommands.
   *
   * @param outStream
   *          The output stream to use for standard output, or <CODE>null</CODE>
   *          if standard output is not needed.
   * @throws ArgumentException
   *           If there is a problem with any of the parameters used
   *           to create this argument.
   */
  public void initializeParser(OutputStream outStream)
      throws ArgumentException
  {
    // Global parameters
    initializeGlobalOption(outStream);
    // ads  Group cli
    cliGroup.add(new DsServiceCliAds());
    // Server Group cli
    cliGroup.add(new DsServiceCliServerGroup());
    // Initialization
    for (DsServiceCliSubCommandGroup oneCli : cliGroup)
    {
      oneCli.initializeCliGroup(this, verboseArg);
    }
  }
  /**
   * Initialize Global option.
   *
   * @param outStream
   *          The output stream used forn the usage.
   * @throws ArgumentException
   *           If there is a problem with any of the parameters used
   *           to create this argument.
   */
  private void initializeGlobalOption(OutputStream outStream)
  throws ArgumentException
  {
    showUsageArg = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
        OPTION_LONG_HELP, MSGID_DESCRIPTION_SHOWUSAGE);
    addGlobalArgument(showUsageArg);
    setUsageArgument(showUsageArg, outStream);
    useSSLArg = new BooleanArgument("useSSL", OPTION_SHORT_USE_SSL,
        OPTION_LONG_USE_SSL, MSGID_DESCRIPTION_USE_SSL);
    addGlobalArgument(useSSLArg);
    hostNameArg = new StringArgument("host", OPTION_SHORT_HOST,
        OPTION_LONG_HOST, false, false, true, OPTION_VALUE_HOST, "localhost",
        null, MSGID_DESCRIPTION_HOST);
    addGlobalArgument(hostNameArg);
    portArg = new IntegerArgument("port", OPTION_SHORT_PORT, OPTION_LONG_PORT,
        false, false, true, OPTION_VALUE_PORT, 389, null,
        MSGID_DESCRIPTION_PORT);
    addGlobalArgument(portArg);
    bindDnArg = new StringArgument("bindDN", OPTION_SHORT_BINDDN,
        OPTION_LONG_BINDDN, false, false, true, OPTION_VALUE_BINDDN,
        "cn=Directory Manager", null, MSGID_DESCRIPTION_BINDDN);
    addGlobalArgument(bindDnArg);
    bindPasswordFileArg = new FileBasedArgument("bindPasswordFile",
        OPTION_SHORT_BINDPWD_FILE, OPTION_LONG_BINDPWD_FILE, false, false,
        OPTION_VALUE_BINDPWD_FILE, null, null,
        MSGID_DESCRIPTION_BINDPASSWORDFILE);
    addGlobalArgument(bindPasswordFileArg);
    verboseArg = new BooleanArgument("verbose", 'v', "verbose",
        MSGID_DESCRIPTION_VERBOSE);
    addGlobalArgument(verboseArg);
  }
  /**
   * Get the host name which has to be used for the command.
   *
   * @return The host name specified by the command line argument, or
   *         the default value, if not specified.
   */
  public String getHostName()
  {
    if (hostNameArg.isPresent())
    {
      return hostNameArg.getValue();
    }
    else
    {
      return hostNameArg.getDefaultValue();
    }
  }
  /**
   * Get the port which has to be used for the command.
   *
   * @return The port specified by the command line argument, or the
   *         default value, if not specified.
   */
  public String getPort()
  {
    if (portArg.isPresent())
    {
      return portArg.getValue();
    }
    else
    {
      return portArg.getDefaultValue();
    }
  }
  /**
   * Get the bindDN which has to be used for the command.
   *
   * @return The bindDN specified by the command line argument, or the
   *         default value, if not specified.
   */
  public String getBindDN()
  {
    if (bindDnArg.isPresent())
    {
      return bindDnArg.getValue();
    }
    else
    {
      return bindDnArg.getDefaultValue();
    }
  }
  /**
   * Get the password which has to be used for the command.
   *
   * @param dn
   *          The user DN for which to password could be asked.
   * @param out
   *          The input stream to used if we have to prompt to the
   *          user.
   * @param err
   *          The error stream to used if we have to prompt to the
   *          user.
   * @return The password stored into the specified file on by the
   *         command line argument, or prompts it if not specified.
   */
  public String getBindPassword(String dn, PrintStream out, PrintStream err)
  {
    if (bindPasswordFileArg.isPresent())
    {
      return bindPasswordFileArg.getValue();
    }
    else
    {
      // read the password from the stdin.
      try
      {
        out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT, dn));
        char[] pwChars = PasswordReader.readPassword();
        return new String(pwChars);
      }
      catch (Exception ex)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
        }
        err.println(wrapText(ex.getMessage(), MAX_LINE_WIDTH));
        return null;
      }
    }
  }
  /**
   * Handle the subcommand.
   *
   * @param adsContext
   *          The context to use to perform ADS operation.
   *
   * @param  outStream         The output stream to use for standard output.
   *
   * @param  errStream         The output stream to use for standard error.
   *
   * @return the return code
   * @throws ADSContextException
   *           If there is a problem with when trying to perform the
   *           operation.
   */
  public int performSubCommand(ADSContext adsContext, OutputStream outStream,
      OutputStream errStream)
    throws ADSContextException
  {
    SubCommand subCmd = getSubCommand();
    for (DsServiceCliSubCommandGroup oneCli : cliGroup)
    {
      if (oneCli.isSubCommand(subCmd))
      {
        return oneCli.performSubCommand(adsContext, subCmd, outStream,
            errStream);
      }
    }
    // Should never occurs: If we are here, it means that the code to
    // handle to subcommand is not yet written.
    return 1;
  }
}
opends/src/ads/org/opends/admin/ads/DsServiceCliServerGroup.java
New file
@@ -0,0 +1,587 @@
/*
 * 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 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.admin.ads;
import static org.opends.server.messages.AdminMessages.*;
import static org.opends.server.tools.ToolConstants.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.admin.ads.ADSContext.ServerGroupProperty;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
/**
 * This class is handling server group CLI.
 */
public class DsServiceCliServerGroup implements DsServiceCliSubCommandGroup
{
  /**
   * End Of Line.
   */
  private String EOL = System.getProperty("line.separator");
  /**
   * The subcommand Parser.
   */
  SubCommandArgumentParser argParser ;
  /**
   * The verbose argument.
   */
  BooleanArgument verboseArg ;
  /**
   * The enumeration containing the different subCommand names.
   */
  private enum SubCommandNameEnum
  {
    /**
     * The create-group subcommand.
     */
    CREATE_GROUP("create-group"),
    /**
     * The delete-group subcommand.
     */
    DELETE_GROUP("delete-group"),
    /**
     * The modify-group subcommand.
     */
    MODIFY_GROUP("modify-group"),
    /**
     * The list-groups subcommand.
     */
    LIST_GROUPS("list-groups"),
    /**
     * The list-members subcommand.
     */
    LIST_MEMBERS("list-members"),
    /**
     * The list-membership subcommand.
     */
    LIST_MEMBERSHIP("list-membership"),
    /**
     * The add-to-group subcommand.
     */
    ADD_TO_GROUP("add-to-group"),
    /**
     * The remove-from-group subcommand.
     */
    REMOVE_FROM_GROUP("remove-from-group");
    // String representation of the value.
    private final String name;
    // Private constructor.
    private SubCommandNameEnum(String name)
    {
      this.name = name;
    }
    /**
     * {@inheritDoc}
     */
    public String toString()
    {
      return name;
    }
    // A lookup table for resolving a unit from its name.
    private static final List<String> nameToSubCmdName ;
    static
    {
      nameToSubCmdName = new ArrayList<String>();
      for (SubCommandNameEnum subCmd : SubCommandNameEnum.values())
      {
        nameToSubCmdName.add(subCmd.toString());
      }
    }
    public static boolean  isSubCommand(String name)
    {
      return nameToSubCmdName.contains(name);
    }
  }
  /**
   * The 'create-group' subcommand.
   */
  public SubCommand createGoupSubCmd;
  /**
   * The 'description' argument of the 'create-group' subcommand.
   */
  private StringArgument createGoupDescriptionArg;
  /**
   * The 'modify-group' subcommand.
   */
  private SubCommand modifyGroupSubCmd;
  /**
   * The 'description' argument of the 'modify-group' subcommand.
   */
  private StringArgument modifyGroupDescriptionArg;
  /**
   * The 'group-id' argument of the 'modify-group' subcommand.
   */
  private StringArgument modifyGroupGroupIdArg;
  /**
   * The 'delete-group' subcommand.
   */
  private SubCommand deleteGroupSubCmd;
  /**
   * The 'list-group' subcommand.
   */
  private SubCommand listGroupSubCmd;
  /**
   * The 'add-to-group' subcommand.
   */
  private SubCommand addToGroupSubCmd;
  /**
   * The 'member-id' argument of the 'add-to-group' subcommand.
   */
  private StringArgument addToGoupMemberIdArg;
  /**
   * The 'remove-from-group' subcommand.
   */
  private SubCommand removeFromGroupSubCmd;
  /**
   * The 'member-id' argument of the 'remove-from-group' subcommand.
   */
  private StringArgument removeFromGoupMemberIdArg;
  /**
   * The 'list-members' subcommand.
   */
  private SubCommand listMembersSubCmd;
  /**
   * The 'mlist-membership' subcommand.
   */
  private SubCommand listMembershipSubCmd;
  /**
   * {@inheritDoc}
   */
  public void initializeCliGroup(SubCommandArgumentParser argParser,
      BooleanArgument verboseArg)
      throws ArgumentException
  {
    this.argParser = argParser ;
    this.verboseArg = verboseArg ;
    // Create-group subcommand
    createGoupSubCmd = new SubCommand(argParser, SubCommandNameEnum.CREATE_GROUP
        .toString(), true, 1, 1, OPERAND_GROUPID,
        MSGID_DSSERVICE_SUBCMD_CREATE_GROUP_DESCRIPTION);
    createGoupDescriptionArg = new StringArgument("description",
        OPTION_SHORT_DESCRIPTION, OPTION_LONG_DESCRIPTION, false, false,
        true, OPTION_VALUE_DESCRIPTION, "", null,
        MSGID_DSSERVICE_ARG_DESCRIPTION_DESCRIPTION);
    createGoupSubCmd.addArgument(createGoupDescriptionArg);
    // modify-group
    modifyGroupSubCmd = new SubCommand(argParser,
        SubCommandNameEnum.MODIFY_GROUP.toString(), true, 1, 1,
        OPERAND_GROUPID, MSGID_DSSERVICE_SUBCMD_MODIFY_GROUP_DESCRIPTION);
    modifyGroupDescriptionArg = new StringArgument("new-description",
        OPTION_SHORT_DESCRIPTION, OPTION_LONG_DESCRIPTION, false, false,
        true, OPTION_VALUE_DESCRIPTION, "", null,
        MSGID_DSSERVICE_ARG_NEW_DESCRIPTION_DESCRIPTION);
    modifyGroupSubCmd.addArgument(modifyGroupDescriptionArg);
    modifyGroupGroupIdArg = new StringArgument("new-groupID",
        OPTION_SHORT_GROUPID, OPTION_LONG_GROUPID, false, false, true,
        OPTION_VALUE_GROUPID, "", null,
        MSGID_DSSERVICE_ARG_NEW_GROUPID_DESCRIPTION);
    modifyGroupSubCmd.addArgument(modifyGroupGroupIdArg);
    // delete-group
    deleteGroupSubCmd = new SubCommand(argParser,SubCommandNameEnum.DELETE_GROUP
        .toString(), true, 1, 1, OPERAND_GROUPID,
        MSGID_DSSERVICE_SUBCMD_DELETE_GROUP_DESCRIPTION);
    // list-groups
    listGroupSubCmd = new SubCommand(argParser, "list-groups",
        MSGID_DSSERVICE_SUBCMD_LIST_GROUPS_DESCRIPTION);
    // add-to-group
    addToGroupSubCmd = new SubCommand(argParser, SubCommandNameEnum.ADD_TO_GROUP
        .toString(), true, 1, 1, OPERAND_GROUPID,
        MSGID_DSSERVICE_SUBCMD_ADD_TO_GROUP_DESCRIPTION);
    addToGoupMemberIdArg = new StringArgument("memberID", OPTION_SHORT_MEMBERID,
        OPTION_LONG_MEMBERID, false, false, true, OPTION_VALUE_MEMBERID, "",
        null, MSGID_DSSERVICE_ARG_ADD_MEMBERID_DESCRIPTION);
    addToGroupSubCmd.addArgument(addToGoupMemberIdArg);
    // remove-from-group
    removeFromGroupSubCmd = new SubCommand(argParser,
        SubCommandNameEnum.REMOVE_FROM_GROUP.toString(), true, 1, 1,
        OPERAND_GROUPID, MSGID_DSSERVICE_SUBCMD_REMOVE_FROM_GROUP_DESCRIPTION);
    removeFromGoupMemberIdArg = new StringArgument("memberID",
        OPTION_SHORT_MEMBERID, OPTION_LONG_MEMBERID, false, false, true,
        OPTION_VALUE_MEMBERID, "", null,
        MSGID_DSSERVICE_ARG_REMOVE_MEMBERID_DESCRIPTION);
    removeFromGroupSubCmd.addArgument(removeFromGoupMemberIdArg);
    // list-members
    listMembersSubCmd = new SubCommand(argParser,SubCommandNameEnum.LIST_MEMBERS
        .toString(), true, 1, 1, OPERAND_GROUPID,
        MSGID_DSSERVICE_SUBCMD_LIST_MEMBERS_DESCRIPTION);
    // list-membership
    listMembershipSubCmd = new SubCommand(argParser,
        SubCommandNameEnum.LIST_MEMBERSHIP.toString(), true, 1, 1,
        OPERAND_MEMBERID, MSGID_DSSERVICE_SUBCMD_LIST_MEMBERSHIP_DESCRIPTION);
  }
  /**
   * {@inheritDoc}
   */
  public boolean isSubCommand(SubCommand subCmd)
  {
      return SubCommandNameEnum.isSubCommand(subCmd.getName());
  }
  /**
   * {@inheritDoc}
   */
  public int performSubCommand(ADSContext adsContext, SubCommand subCmd,
      OutputStream outStream, OutputStream errStream)
      throws ADSContextException
  {
    // -----------------------
    // create-group subcommand
    // -----------------------
    if (subCmd.getName().equals(createGoupSubCmd.getName()))
    {
      String groupId = subCmd.getTrailingArguments().get(0);
      HashMap<ServerGroupProperty, Object> serverGroupProperties =
        new HashMap<ServerGroupProperty, Object>();
      // get the GROUP_ID
      serverGroupProperties.put(ServerGroupProperty.UID, groupId);
      // get the Description
      if (createGoupDescriptionArg.isPresent())
      {
        serverGroupProperties.put(ServerGroupProperty.DESCRIPTION,
            createGoupDescriptionArg.getValue());
      }
      // Create the group
      adsContext.createServerGroup(serverGroupProperties);
      return 0;
    }
    // -----------------------
    // delete-group subcommand
    // -----------------------
    else if (subCmd.getName().equals(deleteGroupSubCmd.getName()))
    {
      String groupId = subCmd.getTrailingArguments().get(0);
      HashMap<ServerGroupProperty, Object> serverGroupProperties =
        new HashMap<ServerGroupProperty, Object>();
      // get the GROUP_ID
      serverGroupProperties.put(ServerGroupProperty.UID, groupId);
      // Delete the group
      adsContext.deleteServerGroup(serverGroupProperties);
      return 0;
    }
    // -----------------------
    // list-group subcommand
    // -----------------------
    else if (subCmd.getName().equals(listGroupSubCmd.getName()))
    {
      Set<Map<ServerGroupProperty, Object>> result = adsContext
          .readServerGroupRegistry();
      StringBuffer buffer = new StringBuffer();
      for (Map<ServerGroupProperty, Object> groupProps : result)
      {
        // Get the group name
        buffer.append(ServerGroupProperty.UID.toString() + " ");
        buffer.append(groupProps.get(ServerGroupProperty.UID));
        buffer.append(EOL);
        if (! verboseArg.isPresent())
        {
          continue;
        }
        // Write other props
        for (ServerGroupProperty propName : groupProps.keySet())
        {
          if ( propName.compareTo(ServerGroupProperty.UID) == 0)
          {
            continue;
          }
          buffer.append("  " + propName.toString() + " ");
          if (propName.compareTo(ServerGroupProperty.MEMBERS) == 0)
          {
            Set atts = (Set)groupProps.get(propName);
            Set<String> membersToPrint = new HashSet<String>(atts.size());
            for (Object att : atts)
            {
              membersToPrint.add(att.toString().substring(3));
            }
            buffer.append(membersToPrint);
          }
          else
          {
            buffer.append(groupProps.get(propName));
          }
          buffer.append(EOL);
        }
      }
      try
      {
        outStream.write(buffer.toString().getBytes());
      }
      catch (IOException e)
      {
      }
      return 0;
    }
    // -----------------------
    // modify-group subcommand
    // -----------------------
    else if (subCmd.getName().equals(modifyGroupSubCmd.getName()))
    {
      String groupId = subCmd.getTrailingArguments().get(0);
      HashMap<ServerGroupProperty, Object> serverGroupProperties =
        new HashMap<ServerGroupProperty, Object>();
      HashSet<ServerGroupProperty> serverGroupPropertiesToRemove =
        new HashSet<ServerGroupProperty>();
      Boolean updateRequired = false;
      Boolean removeRequired = false;
      // get the GROUP_ID
      if (modifyGroupGroupIdArg.isPresent())
      {
        // rename the entry !
        serverGroupProperties.put(ServerGroupProperty.UID, groupId);
      }
      else
      {
        serverGroupProperties.put(ServerGroupProperty.UID, groupId) ;
      }
      // get the Description
      if (modifyGroupDescriptionArg.isPresent())
      {
        String newDesc = modifyGroupDescriptionArg.getValue();
        if (newDesc.length() == 0)
        {
          serverGroupPropertiesToRemove.add(ServerGroupProperty.DESCRIPTION);
          removeRequired = true;
        }
        else
        {
          serverGroupProperties.put(ServerGroupProperty.DESCRIPTION,
              modifyGroupDescriptionArg.getValue());
          updateRequired = true;
        }
      }
      // Update the server group
      if (updateRequired)
      {
        adsContext.updateServerGroup(groupId, serverGroupProperties);
      }
      if (removeRequired)
      {
        adsContext.removeServerGroupProp(groupId,
            serverGroupPropertiesToRemove);
      }
      return 0;
    }
    // -----------------------
    // add-to-group subcommand
    // -----------------------
    else if (subCmd.getName().equals(addToGroupSubCmd.getName()))
    {
      String groupId = subCmd.getTrailingArguments().get(0);
      HashMap<ServerGroupProperty, Object> serverGroupProperties =
        new HashMap<ServerGroupProperty, Object>();
      // get the current member list
      Set<String> memberList = adsContext.getServerGroupMemberList(groupId);
      if (memberList == null)
      {
        memberList = new HashSet<String>();
      }
      memberList.add("cn=" + addToGoupMemberIdArg.getValue());
      serverGroupProperties.put(ServerGroupProperty.MEMBERS, memberList);
      // Update the server group
      adsContext.updateServerGroup(groupId, serverGroupProperties);
      return 0;
    }
    // -----------------------
    // remove-from-group subcommand
    // -----------------------
    else if (subCmd.getName().equals(removeFromGroupSubCmd.getName()))
    {
      String groupId = subCmd.getTrailingArguments().get(0);
      HashMap<ServerGroupProperty, Object> serverGroupProperties =
        new HashMap<ServerGroupProperty, Object>();
      // get the current member list
      Set<String> memberList = adsContext.getServerGroupMemberList(groupId);
      if (memberList == null)
      {
        // TODO Error message
        return 1;
      }
      String memberToRemove = "cn=" + removeFromGoupMemberIdArg.getValue();
      if (! memberList.contains(memberToRemove))
      {
        // TODO Error message
        return 1;
      }
      memberList.remove(memberToRemove);
      serverGroupProperties.put(ServerGroupProperty.MEMBERS, memberList);
      // Update the server group
      adsContext.updateServerGroup(groupId, serverGroupProperties);
      return 0;
    }
    // -----------------------
    // list-members subcommand
    // -----------------------
    else if (subCmd.getName().equals(listMembersSubCmd.getName()))
    {
      String groupId = subCmd.getTrailingArguments().get(0);
      // get the current member list
      Set<String> memberList = adsContext.getServerGroupMemberList(groupId);
      if (memberList == null)
      {
        return 0;
      }
      StringBuffer buffer = new StringBuffer();
      for (String member : memberList)
      {
        buffer.append(member.substring(3));
        buffer.append(EOL);
      }
      try
      {
        outStream.write(buffer.toString().getBytes());
      }
      catch (IOException e)
      {
      }
      return 0;
    }
    // -----------------------
    // list-membership subcommand
    // -----------------------
    else if (subCmd.getName().equals(listMembershipSubCmd.getName()))
    {
      Set<Map<ServerGroupProperty, Object>> result = adsContext
          .readServerGroupRegistry();
      String MemberId = subCmd.getTrailingArguments().get(0);
      StringBuffer buffer = new StringBuffer();
      for (Map<ServerGroupProperty, Object> groupProps : result)
      {
        // Get the group name;
        String groupId = groupProps.get(ServerGroupProperty.UID).toString();
        // look for memeber list attribute
        for (ServerGroupProperty propName : groupProps.keySet())
        {
          if ( propName.compareTo(ServerGroupProperty.MEMBERS) != 0)
          {
            continue;
          }
          // Check if the member list contains the member-id
            Set atts = (Set)groupProps.get(propName);
            for (Object att : atts)
            {
              if (att.toString().substring(3).toLowerCase().equals(
                MemberId.toLowerCase()))
            {
              buffer.append(groupId);
              buffer.append(EOL);
              break;
            }
            }
            break ;
        }
      }
      try
      {
        outStream.write(buffer.toString().getBytes());
      }
      catch (IOException e)
      {
      }
      return 0;
    }
    // Should never occurs: If we are here, it means that the code to
    // handle to subcommand is not yet written.
    return 1;
  }
}
opends/src/ads/org/opends/admin/ads/DsServiceCliSubCommandGroup.java
New file
@@ -0,0 +1,85 @@
/*
 * 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 2006-2007 Sun Microsystems, Inc.
 */
 package org.opends.admin.ads;
import java.io.OutputStream;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
/**
 * This Interface defines method that a group of subcommand shoud implement.
 */
public interface DsServiceCliSubCommandGroup
{
  /**
   * Initialize subcommand related to server group management.
   *
   * @param argParser
   *          The parser in which we should be registered.
   * @param verboseArg
   *          The verbose Argument.
   * @throws ArgumentException
   *           If there is a problem with any of the parameters used
   *           to create this argument.
   */
  public abstract void initializeCliGroup(SubCommandArgumentParser argParser,
      BooleanArgument verboseArg) throws ArgumentException;
  /**
   * Indicates if the provided suncommand is part of this group.
   *
   * @param subCmd
   *          The actual subcommand with input parameter.
   * @return True if the provided suncommand is part of this group.
   */
  public abstract boolean isSubCommand(SubCommand subCmd);
  /**
   * Handle the subcommand.
   * @param adsContext
   *          The context to use to perform ADS operation.
   * @param subCmd
   *          The actual subcommand with input parameter
   *
   * @param  outStream         The output stream to use for standard output.
   *
   * @param  errStream         The output stream to use for standard error.
   *
   * @return the return code
   * @throws ADSContextException
   *           If there is a problem with when trying to perform the
   *           operation.
   */
  public abstract int performSubCommand(ADSContext adsContext,
      SubCommand subCmd, OutputStream outStream, OutputStream errStream)
      throws ADSContextException;
}
opends/src/server/org/opends/server/messages/AdminMessages.java
@@ -306,6 +306,29 @@
  public static final int MSGID_DSSERVICE_SUBCMD_LIST_MEMBERSHIP_DESCRIPTION =
    CATEGORY_MASK_ADMIN | SEVERITY_MASK_INFORMATIONAL | 31;
  /**
   * The message ID for the message that will be used if the
   * client CLI cannot contact the ADS. This does one take argument.
   */
  public static final int MSGID_DSSERVICE_CANNOT_CONNECT_TO_ADS =
    CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 32;
  /**
   * The message ID for the message that will be used as the description for the
   * create-ads subcommand part of dsservice tool.
   * This does not take any arguments.
   */
  public static final int MSGID_DSSERVICE_SUBCMD_CREATE_ADS_DESCRIPTION =
    CATEGORY_MASK_ADMIN | SEVERITY_MASK_INFORMATIONAL | 33;
  /**
   * The message ID for the message that will be used as the description for the
   * delete-ads subcommand part of dsservice tool.
   * This does not take any arguments.
   */
  public static final int MSGID_DSSERVICE_SUBCMD_DELETE_ADS_DESCRIPTION =
    CATEGORY_MASK_ADMIN | SEVERITY_MASK_INFORMATIONAL | 34;
  // Prevent instantiation.
  private AdminMessages() {
    // Do nothing.
@@ -427,6 +450,12 @@
        "List members of the specified group" );
    registerMessage(MSGID_DSSERVICE_SUBCMD_LIST_MEMBERSHIP_DESCRIPTION,
        "List groups in which the specified server is a member" );
    registerMessage(MSGID_DSSERVICE_CANNOT_CONNECT_TO_ADS,
        "Could not connect to %s. Check that the "+
        "server is running and that the provided credentials are valid");
    registerMessage(MSGID_DSSERVICE_SUBCMD_CREATE_ADS_DESCRIPTION,
        "Create a new ADS DN");
    registerMessage(MSGID_DSSERVICE_SUBCMD_DELETE_ADS_DESCRIPTION,
         "Delete an existing ADS DN");
  }
}
opends/src/server/org/opends/server/tools/ToolConstants.java
@@ -570,5 +570,11 @@
   * displayed in usage information.
   */
  public static final String OPERAND_MEMBERID = "MEMBER_ID";
  /**
   * The placeholder value of backend name that will be
   * displayed in usage information.
   */
  public static final String OPERAND_BACKEND = "BACKEND_NAME";
}