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

jvergara
17.11.2009 013494192c189ce5bd101f198c4d33230374d4b8
Fix for issue 3601 (Control Panel: unable to modify schema objects or attributes)

The following changes allow the user to edit and modify attributes and objectclasses (those that are considered not part of the configuration or standard schema).

With these changes the user can modify any property of the objectclass and the attributes, references to the modified elements (for instance when they are renamed) are updated in the schema.

These modifications also allow to delete schema elements that are referenced elsewhere in the schema. Before the changes for instance deleting an attribute included in the definition of an object class was not allowed. With these changes, the user is informed of the existing dependencies, but he/she is allowed to proceed with the deletion of the attribute (the references will be automatically removed).
1 files deleted
3 files added
11 files modified
5646 ■■■■ changed files
opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteSchemaElementsTask.java 444 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyAttributeTask.java 328 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyObjectClassTask.java 255 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/NewSchemaElementsTask.java 824 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/SchemaTask.java 295 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java 56 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/BrowseSchemaPanel.java 409 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/CustomAttributePanel.java 1147 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/CustomObjectClassPanel.java 1061 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/NewAttributePanel.java 307 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/NewObjectClassPanel.java 298 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/SchemaBrowserRightPanel.java 43 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java 46 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/util/ControlPanelLog.java 4 ●●●● patch | view | raw | blame | history
opends/src/messages/messages/admin_tool.properties 129 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteSchemaElementsTask.java
@@ -32,8 +32,12 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.naming.NamingException;
@@ -60,6 +64,7 @@
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OpenDsException;
import org.opends.server.types.Schema;
import org.opends.server.types.SchemaFileElement;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
@@ -69,24 +74,94 @@
 */
public class DeleteSchemaElementsTask extends Task
{
  ArrayList<ObjectClass> ocsToDelete = new ArrayList<ObjectClass>();
  ArrayList<AttributeType> attrsToDelete = new ArrayList<AttributeType>();
  private Set<String> backendSet;
  // The list of object classes that the user asked to delete.
  LinkedHashSet<ObjectClass> providedOcsToDelete =
    new LinkedHashSet<ObjectClass>();
  // The list of attributes that the user asked to delete.
  LinkedHashSet<AttributeType> providedAttrsToDelete =
    new LinkedHashSet<AttributeType>();
  // The list of object classes that will be actually deleted (some might be
  // recreated).
  LinkedHashSet<ObjectClass> ocsToDelete = new LinkedHashSet<ObjectClass>();
  // The list of attributes that will be actually deleted (some might be
  // recreated).
  LinkedHashSet<AttributeType> attrsToDelete =
    new LinkedHashSet<AttributeType>();
  // The list of object classes that will be recreated.
  LinkedHashSet<ObjectClass> ocsToAdd = new LinkedHashSet<ObjectClass>();
  // The list of attributes that will be recreated.
  LinkedHashSet<AttributeType> attrsToAdd = new LinkedHashSet<AttributeType>();
  /**
   * Constructor of the task.
   * @param info the control panel information.
   * @param dlg the progress dialog where the task progress will be displayed.
   * @param ocsToDelete the object classes that must be deleted.
   * @param attrsToDelete the attributes that must be deleted.
   * @param ocsToDelete the object classes that must be deleted (ordered).
   * @param attrsToDelete the attributes that must be deleted (ordered).
   */
  public DeleteSchemaElementsTask(ControlPanelInfo info, ProgressDialog dlg,
      List<ObjectClass> ocsToDelete, List<AttributeType> attrsToDelete)
      LinkedHashSet<ObjectClass> ocsToDelete,
      LinkedHashSet<AttributeType> attrsToDelete)
  {
    super(info, dlg);
    this.ocsToDelete.addAll(ocsToDelete);
    this.attrsToDelete.addAll(attrsToDelete);
    backendSet = new HashSet<String>();
    this.providedOcsToDelete.addAll(ocsToDelete);
    this.providedAttrsToDelete.addAll(attrsToDelete);
    Schema schema = info.getServerDescriptor().getSchema();
    LinkedHashSet<AttributeType> allAttrsToDelete =
      DeleteSchemaElementsTask.getOrderedAttributesToDelete(attrsToDelete,
          schema);
    LinkedHashSet<ObjectClass> allOcsToDelete = null;
    if (!attrsToDelete.isEmpty())
    {
      allOcsToDelete =
        DeleteSchemaElementsTask.getOrderedObjectClassesToDeleteFromAttrs(
          attrsToDelete, schema);
    }
    if (!ocsToDelete.isEmpty())
    {
      if (allOcsToDelete == null)
      {
      allOcsToDelete =
        DeleteSchemaElementsTask.getOrderedObjectClassesToDelete(
            ocsToDelete, schema);
      }
      else
      {
        allOcsToDelete.addAll(
            DeleteSchemaElementsTask.getOrderedObjectClassesToDelete(
                ocsToDelete, schema));
      }
    }
    ArrayList<AttributeType> lAttrsToDelete =
      new ArrayList<AttributeType>(allAttrsToDelete);
    for (int i = lAttrsToDelete.size() - 1; i >= 0; i--)
    {
      AttributeType attrToDelete = lAttrsToDelete.get(i);
      if (!attrsToDelete.contains(attrToDelete))
      {
        AttributeType attrToAdd = getAttributeToAdd(attrToDelete);
        if (attrToAdd != null)
        {
          attrsToAdd.add(attrToAdd);
        }
      }
    }
    ArrayList<ObjectClass> lOcsToDelete =
      new ArrayList<ObjectClass>(allOcsToDelete);
    for (int i = lOcsToDelete.size() - 1; i >= 0; i--)
    {
      ObjectClass ocToDelete = lOcsToDelete.get(i);
      if (!ocsToDelete.contains(ocToDelete))
      {
        ocsToAdd.add(getObjectClassToAdd(lOcsToDelete.get(i)));
      }
    }
    this.ocsToDelete.addAll(allOcsToDelete);
    this.attrsToDelete.addAll(allAttrsToDelete);
  }
  /**
@@ -94,7 +169,7 @@
   */
  public Set<String> getBackends()
  {
    return backendSet;
    return Collections.emptySet();
  }
  /**
@@ -103,7 +178,17 @@
  public boolean canLaunch(Task taskToBeLaunched,
      Collection<Message> incompatibilityReasons)
  {
    return true;
    boolean canLaunch = true;
    if (state == State.RUNNING &&
        (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT))
    {
      incompatibilityReasons.add(getIncompatibilityMessage(this,
            taskToBeLaunched));
      canLaunch = false;
    }
    return canLaunch;
  }
  /**
@@ -111,18 +196,7 @@
   */
  public Type getType()
  {
    if (attrsToDelete.isEmpty())
    {
      return Type.DELETE_OBJECTCLASS;
    }
    else if (ocsToDelete.isEmpty())
    {
      return Type.DELETE_ATTRIBUTE;
    }
    else
    {
      return Type.DELETE_OBJECTCLASS;
    }
    return Type.NEW_SCHEMA_ELEMENT;
  }
  /**
@@ -156,9 +230,9 @@
  /**
   * {@inheritDoc}
   */
  protected ArrayList<String> getCommandLineArguments()
  protected List<String> getCommandLineArguments()
  {
    return new ArrayList<String>();
    return Collections.emptyList();
  }
  /**
@@ -178,8 +252,9 @@
    final boolean[] isFirst = {true};
    final int totalNumber = ocsToDelete.size() + attrsToDelete.size();
    int numberDeleted = 0;
    for (final ObjectClass objectClass : ocsToDelete)
    for (ObjectClass objectClass : ocsToDelete)
    {
      final ObjectClass fObjectclass = objectClass;
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
@@ -189,11 +264,11 @@
            getProgressDialog().appendProgressHtml("<br><br>");
          }
          isFirst[0] = false;
          printEquivalentCommandToDelete(objectClass);
          printEquivalentCommandToDelete(fObjectclass);
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_DELETING_OBJECTCLASS.get(
                  objectClass.getNameOrOID()),
                      fObjectclass.getNameOrOID()),
                  ColorAndFontConstants.progressFont));
        }
      });
@@ -236,8 +311,9 @@
      });
    }
    for (final AttributeType attribute : attrsToDelete)
    for (AttributeType attribute : attrsToDelete)
    {
      final AttributeType fAttribute = attribute;
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
@@ -247,11 +323,11 @@
            getProgressDialog().appendProgressHtml("<br><br>");
          }
          isFirst[0] = false;
          printEquivalentCommandToDelete(attribute);
          printEquivalentCommandToDelete(fAttribute);
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_DELETING_ATTRIBUTE.get(
                  attribute.getNameOrOID()),
                      fAttribute.getNameOrOID()),
                  ColorAndFontConstants.progressFont));
        }
      });
@@ -296,6 +372,25 @@
      });
    }
    if (!ocsToAdd.isEmpty() || !attrsToAdd.isEmpty())
    {
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          getProgressDialog().appendProgressHtml(Utilities.applyFont(
              "<br><br>"+
              INFO_CTRL_PANEL_EXPLANATION_TO_DELETE_REFERENCED_ELEMENTS.get()+
              "<br><br>",
              ColorAndFontConstants.progressFont));
        }
      });
      NewSchemaElementsTask createTask =
        new NewSchemaElementsTask(getInfo(), getProgressDialog(), ocsToAdd,
            attrsToAdd);
      createTask.runTask();
    }
  }
  /**
@@ -431,9 +526,19 @@
    String attrValue = getSchemaFileAttributeValue(element);
    if (!isServerRunning())
    {
      Message msg;
      if (element instanceof AttributeType)
      {
        msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_ATTRIBUTE_OFFLINE.get(
            element.getNameOrOID(), schemaFile);
      }
      else
      {
        msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_OBJECTCLASS_OFFLINE.get(
            element.getNameOrOID(), schemaFile);
      }
      getProgressDialog().appendProgressHtml(Utilities.applyFont(
          INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_SCHEMA_ELEMENT_OFFLINE.get(
              schemaFile)+"<br><b>"+
          msg+"<br><b>"+
          attrName+": "+attrValue+"</b><br><br>",
          ColorAndFontConstants.progressFont));
    }
@@ -447,10 +552,21 @@
      String equiv = getEquivalentCommandLine(getCommandLinePath("ldapmodify"),
          args);
      Message msg;
      if (element instanceof AttributeType)
      {
        msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_ATTRIBUTE_ONLINE.get(
            element.getNameOrOID());
      }
      else
      {
        msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_OBJECTCLASS_ONLINE.get(
            element.getNameOrOID());
      }
      StringBuilder sb = new StringBuilder();
      sb.append(
          INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_SCHEMA_ELEMENT_ONLINE.get()+
          "<br><b>");
          msg+"<br><b>");
      sb.append(equiv);
      sb.append("<br>");
      sb.append("dn: cn=schema<br>");
@@ -462,4 +578,262 @@
          ColorAndFontConstants.progressFont));
    }
  }
  private AttributeType getAttributeToAdd(AttributeType attrToDelete)
  {
    AttributeType attrToAdd;
    boolean isSuperior = false;
    AttributeType newSuperior = attrToDelete.getSuperiorType();
    for (AttributeType attr : providedAttrsToDelete)
    {
      if (attr.equals(attrToDelete.getSuperiorType()))
      {
        isSuperior = true;
        newSuperior = attr.getSuperiorType();
        while (newSuperior != null &&
            providedAttrsToDelete.contains(newSuperior))
        {
          newSuperior = newSuperior.getSuperiorType();
        }
        break;
      }
    }
    if (isSuperior)
    {
      ArrayList<String> allNames = new ArrayList<String>();
      for (String str : attrToDelete.getNormalizedNames())
      {
        allNames.add(str);
      }
      Map<String, List<String>> extraProperties =
        cloneExtraProperties(attrToDelete);
      attrToAdd = new AttributeType(
          "",
          attrToDelete.getPrimaryName(),
          allNames,
          attrToDelete.getOID(),
          attrToDelete.getDescription(),
          null,
          attrToDelete.getSyntax(),
          attrToDelete.getApproximateMatchingRule(),
          attrToDelete.getEqualityMatchingRule(),
          attrToDelete.getOrderingMatchingRule(),
          attrToDelete.getSubstringMatchingRule(),
          attrToDelete.getUsage(),
          attrToDelete.isCollective(),
          attrToDelete.isNoUserModification(),
          attrToDelete.isObsolete(),
          attrToDelete.isSingleValue(),
          extraProperties);
    }
    else
    {
      // Nothing to be changed in the definition of the attribute itself.
      attrToAdd = attrToDelete;
    }
    return attrToAdd;
  }
  private ObjectClass getObjectClassToAdd(ObjectClass ocToDelete)
  {
    ObjectClass ocToAdd;
    boolean containsAttribute = false;
    for (AttributeType attr : providedAttrsToDelete)
    {
      if(ocToDelete.getRequiredAttributeChain().contains(attr) ||
      ocToDelete.getOptionalAttributeChain().contains(attr))
      {
        containsAttribute = true;
        break;
      }
    }
    boolean hasSuperior = false;
    ObjectClass newSuperior = ocToDelete.getSuperiorClass();
    for (ObjectClass oc : providedOcsToDelete)
    {
      if (ocToDelete.getSuperiorClass().equals(oc))
      {
        hasSuperior = true;
        newSuperior = oc.getSuperiorClass();
        while (newSuperior != null &&
            providedOcsToDelete.contains(newSuperior))
        {
          newSuperior = newSuperior.getSuperiorClass();
        }
        break;
      }
    }
    if (containsAttribute || hasSuperior)
    {
      ArrayList<String> allNames = new ArrayList<String>();
      for (String str : ocToDelete.getNormalizedNames())
      {
        allNames.add(str);
      }
      Map<String, List<String>> extraProperties =
        cloneExtraProperties(ocToDelete);
      Set<AttributeType> required;
      Set<AttributeType> optional;
      if (containsAttribute)
      {
        required = new HashSet<AttributeType>(
            ocToDelete.getRequiredAttributes());
        optional = new HashSet<AttributeType>(
            ocToDelete.getOptionalAttributes());
        required.removeAll(providedAttrsToDelete);
        optional.removeAll(providedAttrsToDelete);
      }
      else
      {
        required = ocToDelete.getRequiredAttributes();
        optional = ocToDelete.getOptionalAttributes();
      }
      ocToAdd = new ObjectClass("",
          ocToDelete.getPrimaryName(),
          allNames,
          ocToDelete.getOID(),
          ocToDelete.getDescription(),
          newSuperior,
          required,
          optional,
          ocToDelete.getObjectClassType(),
          ocToDelete.isObsolete(),
          extraProperties);
    }
    else
    {
      // Nothing to be changed in the definition of the object class itself.
      ocToAdd = ocToDelete;
    }
    return ocToAdd;
  }
  /**
   * Returns an ordered set of the attributes that must be deleted.
   * @param attrsToDelete the attributes to be deleted.
   * @param schema the server schema.
   * @return an ordered list of the attributes that must be deleted.
   */
  public static LinkedHashSet<AttributeType> getOrderedAttributesToDelete(
      Collection<AttributeType> attrsToDelete, Schema schema)
  {
    LinkedHashSet<AttributeType> orderedAttributes =
      new LinkedHashSet<AttributeType>();
    for (AttributeType attribute : attrsToDelete)
    {
      orderedAttributes.addAll(getOrderedChildrenToDelete(attribute, schema));
      orderedAttributes.add(attribute);
    }
    return orderedAttributes;
  }
  /**
   * Returns an ordered list of the object classes that must be deleted.
   * @param ocsToDelete the object classes to be deleted.
   * @param schema the server schema.
   * @return an ordered list of the object classes that must be deleted.
   */
  public static LinkedHashSet<ObjectClass> getOrderedObjectClassesToDelete(
      Collection<ObjectClass> ocsToDelete, Schema schema)
  {
    LinkedHashSet<ObjectClass> orderedOcs = new LinkedHashSet<ObjectClass>();
    for (ObjectClass oc : ocsToDelete)
    {
      orderedOcs.addAll(getOrderedChildrenToDelete(oc, schema));
      orderedOcs.add(oc);
    }
    return orderedOcs;
  }
  /**
   * Returns an ordered list of the object classes that must be deleted when
   * deleting a list of attributes that must be deleted.
   * @param attrsToDelete the attributes to be deleted.
   * @param schema the server schema.
   * @return an ordered list of the object classes that must be deleted when
   * deleting a list of attributes that must be deleted.
   */
  public static LinkedHashSet<ObjectClass>
  getOrderedObjectClassesToDeleteFromAttrs(
      Collection<AttributeType> attrsToDelete, Schema schema)
  {
    LinkedHashSet<ObjectClass> orderedOcs = new LinkedHashSet<ObjectClass>();
    ArrayList<ObjectClass> dependentClasses = new ArrayList<ObjectClass>();
    for (AttributeType attr : attrsToDelete)
    {
      for (ObjectClass oc : schema.getObjectClasses().values())
      {
        if (oc.getRequiredAttributeChain().contains(attr))
        {
          dependentClasses.add(oc);
        }
        else if (oc.getOptionalAttributeChain().contains(attr))
        {
          dependentClasses.add(oc);
        }
      }
    }
    for (ObjectClass oc : dependentClasses)
    {
      orderedOcs.addAll(getOrderedChildrenToDelete(oc, schema));
      orderedOcs.add(oc);
    }
    return orderedOcs;
  }
  /**
   * Clones the extra properties of the provided schema element.  This can
   * be used when copying schema elements.
   * @param element the schema element.
   * @return the extra properties of the provided schema element.
   */
  public static Map<String, List<String>> cloneExtraProperties(
      CommonSchemaElements element)
  {
    Map<String, List<String>> extraProperties =
      new HashMap<String, List<String>>();
    for (String name : element.getExtraPropertyNames())
    {
      List<String> values = new ArrayList<String>();
      Iterable<String> properties = element.getExtraProperty(name);
      for (String v : properties)
      {
        values.add(v);
      }
      extraProperties.put(name, values);
    }
    return extraProperties;
  }
  private static LinkedHashSet<AttributeType> getOrderedChildrenToDelete(
      AttributeType attribute, Schema schema)
  {
    LinkedHashSet<AttributeType> children = new LinkedHashSet<AttributeType>();
    for (AttributeType attr : schema.getAttributeTypes().values())
    {
      if (attribute.equals(attr.getSuperiorType()))
      {
        children.addAll(getOrderedChildrenToDelete(attr, schema));
        children.add(attr);
      }
    }
    return children;
  }
  private static LinkedHashSet<ObjectClass> getOrderedChildrenToDelete(
      ObjectClass objectClass, Schema schema)
  {
    LinkedHashSet<ObjectClass> children = new LinkedHashSet<ObjectClass>();
    for (ObjectClass oc : schema.getObjectClasses().values())
    {
      if (objectClass.equals(oc.getSuperiorClass()))
      {
        children.addAll(getOrderedChildrenToDelete(oc, schema));
        children.add(oc);
      }
    }
    return children;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyAttributeTask.java
New file
@@ -0,0 +1,328 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.task;
import static org.opends.messages.AdminToolMessages.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.SwingUtilities;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
import org.opends.guitools.controlpanel.ui.ProgressDialog;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OpenDsException;
import org.opends.server.types.Schema;
/**
 * The task that is in charge of modifying an attribute definition (and all
 * the references to this attribute).
 *
 */
public class ModifyAttributeTask extends Task
{
  private AttributeType oldAttribute;
  private AttributeType newAttribute;
  /**
   * The constructor of the task.
   * @param info the control panel info.
   * @param dlg the progress dialog that shows the progress of the task.
   * @param oldAttribute the old attribute definition.
   * @param newAttribute the new attribute definition.
   */
  public ModifyAttributeTask(ControlPanelInfo info, ProgressDialog dlg,
      AttributeType oldAttribute, AttributeType newAttribute)
  {
    super(info, dlg);
    if (oldAttribute == null)
    {
      throw new IllegalArgumentException("oldAttribute cannot be null.");
    }
    if (newAttribute == null)
    {
      throw new IllegalArgumentException("newAttribute cannot be null.");
    }
    this.oldAttribute = oldAttribute;
    this.newAttribute = newAttribute;
  }
  /**
   * {@inheritDoc}
   */
  public Type getType()
  {
    return Type.MODIFY_SCHEMA_ELEMENT;
  }
  /**
   * {@inheritDoc}
   */
  public Message getTaskDescription()
  {
    return INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TASK_DESCRIPTION.get(
        oldAttribute.getNameOrOID());
  }
  /**
   * {@inheritDoc}
   */
  public boolean canLaunch(Task taskToBeLaunched,
      Collection<Message> incompatibilityReasons)
  {
    boolean canLaunch = true;
    if (state == State.RUNNING &&
        (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT))
    {
      incompatibilityReasons.add(getIncompatibilityMessage(this,
            taskToBeLaunched));
      canLaunch = false;
    }
    return canLaunch;
  }
  /**
   * {@inheritDoc}
   */
  public Set<String> getBackends()
  {
    return Collections.emptySet();
  }
  /**
   * {@inheritDoc}
   */
  protected List<String> getCommandLineArguments()
  {
    return Collections.emptyList();
  }
  /**
   * {@inheritDoc}
   */
  protected String getCommandLinePath()
  {
    return null;
  }
  /**
   * {@inheritDoc}
   */
  public void runTask()
  {
    try
    {
      updateSchema();
      state = State.FINISHED_SUCCESSFULLY;
    }
    catch (Throwable t)
    {
      // TODO
      //revertChanges();
      lastException = t;
      state = State.FINISHED_WITH_ERROR;
    }
  }
  private AttributeType getAttributeToAdd(AttributeType attrToDelete)
  {
    AttributeType attrToAdd;
    if (attrToDelete.equals(oldAttribute))
    {
      attrToAdd = newAttribute;
    }
    else
    {
      if (oldAttribute.equals(attrToDelete.getSuperiorType()))
      {
        ArrayList<String> allNames = new ArrayList<String>();
        for (String str : attrToDelete.getNormalizedNames())
        {
          allNames.add(str);
        }
        Map<String, List<String>> extraProperties =
          DeleteSchemaElementsTask.cloneExtraProperties(attrToDelete);
        AttributeType newSuperior = newAttribute;
        attrToAdd = new AttributeType(
            "",
            attrToDelete.getPrimaryName(),
            allNames,
            attrToDelete.getOID(),
            attrToDelete.getDescription(),
            newSuperior,
            attrToDelete.getSyntax(),
            attrToDelete.getApproximateMatchingRule(),
            attrToDelete.getEqualityMatchingRule(),
            attrToDelete.getOrderingMatchingRule(),
            attrToDelete.getSubstringMatchingRule(),
            attrToDelete.getUsage(),
            attrToDelete.isCollective(),
            attrToDelete.isNoUserModification(),
            attrToDelete.isObsolete(),
            attrToDelete.isSingleValue(),
            extraProperties);
      }
      else
      {
        // Nothing to be changed in the definition of the attribute itself.
        attrToAdd = attrToDelete;
      }
    }
    return attrToAdd;
  }
  private ObjectClass getObjectClassToAdd(ObjectClass ocToDelete)
  {
    ObjectClass ocToAdd;
    boolean containsAttribute =
      ocToDelete.getRequiredAttributeChain().contains(oldAttribute) ||
      ocToDelete.getOptionalAttributeChain().contains(oldAttribute);
    if (containsAttribute)
    {
      ArrayList<String> allNames = new ArrayList<String>();
      for (String str : ocToDelete.getNormalizedNames())
      {
        allNames.add(str);
      }
      Map<String, List<String>> extraProperties =
        DeleteSchemaElementsTask.cloneExtraProperties(ocToDelete);
      Set<AttributeType> required = new HashSet<AttributeType>(
          ocToDelete.getRequiredAttributes());
      Set<AttributeType> optional = new HashSet<AttributeType>(
          ocToDelete.getOptionalAttributes());
      if (required.contains(oldAttribute))
      {
        required.remove(oldAttribute);
        required.add(newAttribute);
      }
      else if (optional.contains(oldAttribute))
      {
        optional.remove(oldAttribute);
        optional.add(newAttribute);
      }
      ocToAdd = new ObjectClass("",
          ocToDelete.getPrimaryName(),
          allNames,
          ocToDelete.getOID(),
          ocToDelete.getDescription(),
          ocToDelete.getSuperiorClass(),
          required,
          optional,
          ocToDelete.getObjectClassType(),
          ocToDelete.isObsolete(),
          extraProperties);
    }
    else
    {
      // Nothing to be changed in the definition of the object class itself.
      ocToAdd = ocToDelete;
    }
    return ocToAdd;
  }
  /**
   * Updates the schema.
   * @throws OpenDsException if an error occurs.
   */
  private void updateSchema() throws OpenDsException
  {
    Schema schema = getInfo().getServerDescriptor().getSchema();
    ArrayList<AttributeType> attrs = new ArrayList<AttributeType>();
    attrs.add(oldAttribute);
    LinkedHashSet<AttributeType> attrsToDelete =
      DeleteSchemaElementsTask.getOrderedAttributesToDelete(attrs, schema);
    LinkedHashSet<ObjectClass> ocsToDelete =
      DeleteSchemaElementsTask.getOrderedObjectClassesToDeleteFromAttrs(
          attrsToDelete, schema);
    LinkedHashSet<AttributeType> attrsToAdd =
      new LinkedHashSet<AttributeType>();
    ArrayList<AttributeType> lAttrsToDelete =
      new ArrayList<AttributeType>(attrsToDelete);
    for (int i = lAttrsToDelete.size() - 1; i >= 0; i--)
    {
      AttributeType attrToAdd = getAttributeToAdd(lAttrsToDelete.get(i));
      if (attrToAdd != null)
      {
        attrsToAdd.add(attrToAdd);
      }
    }
    ArrayList<ObjectClass> lOcsToDelete =
      new ArrayList<ObjectClass>(ocsToDelete);
    LinkedHashSet<ObjectClass> ocsToAdd = new LinkedHashSet<ObjectClass>();
    for (int i = lOcsToDelete.size() - 1; i >= 0; i--)
    {
      ocsToAdd.add(getObjectClassToAdd(lOcsToDelete.get(i)));
    }
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(Utilities.applyFont(
            INFO_CTRL_PANEL_EXPLANATION_TO_MODIFY_ATTRIBUTE.get(
                oldAttribute.getNameOrOID())+"<br><br>",
                ColorAndFontConstants.progressFont));
      }
    });
    DeleteSchemaElementsTask deleteTask =
      new DeleteSchemaElementsTask(getInfo(), getProgressDialog(), ocsToDelete,
          attrsToDelete);
    deleteTask.runTask();
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>",
                ColorAndFontConstants.progressFont));
      }
    });
    NewSchemaElementsTask createTask =
      new NewSchemaElementsTask(getInfo(), getProgressDialog(), ocsToAdd,
          attrsToAdd);
    createTask.runTask();
    notifyConfigurationElementCreated(newAttribute);
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyObjectClassTask.java
New file
@@ -0,0 +1,255 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.task;
import static org.opends.messages.AdminToolMessages.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.SwingUtilities;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
import org.opends.guitools.controlpanel.ui.ProgressDialog;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OpenDsException;
import org.opends.server.types.Schema;
/**
 * The task that is in charge of modifying an object class definition (and all
 * the references to this object class).
 *
 */
public class ModifyObjectClassTask extends Task
{
  private ObjectClass oldObjectClass;
  private ObjectClass newObjectClass;
  /**
   * The constructor of the task.
   * @param info the control panel info.
   * @param dlg the progress dialog that shows the progress of the task.
   * @param oldObjectClass the old object class definition.
   * @param newObjectClass the new object class definition.
   */
  public ModifyObjectClassTask(ControlPanelInfo info, ProgressDialog dlg,
      ObjectClass oldObjectClass, ObjectClass newObjectClass)
  {
    super(info, dlg);
    this.oldObjectClass = oldObjectClass;
    this.newObjectClass = newObjectClass;
    if (oldObjectClass == null)
    {
      throw new IllegalArgumentException("oldObjectClass cannot be null.");
    }
    if (newObjectClass == null)
    {
      throw new IllegalArgumentException("newObjectClass cannot be null.");
    }
  }
  /**
   * {@inheritDoc}
   */
  public Type getType()
  {
    return Type.MODIFY_SCHEMA_ELEMENT;
  }
  /**
   * {@inheritDoc}
   */
  public Message getTaskDescription()
  {
    return INFO_CTRL_PANEL_MODIFY_OBJECTCLASS_TASK_DESCRIPTION.get(
        oldObjectClass.getNameOrOID());
  }
  /**
   * {@inheritDoc}
   */
  public boolean canLaunch(Task taskToBeLaunched,
      Collection<Message> incompatibilityReasons)
  {
    boolean canLaunch = true;
    if (state == State.RUNNING &&
        (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT))
    {
      incompatibilityReasons.add(getIncompatibilityMessage(this,
            taskToBeLaunched));
      canLaunch = false;
    }
    return canLaunch;
  }
  /**
   * {@inheritDoc}
   */
  public Set<String> getBackends()
  {
    return Collections.emptySet();
  }
  /**
   * {@inheritDoc}
   */
  protected List<String> getCommandLineArguments()
  {
    return Collections.emptyList();
  }
  /**
   * {@inheritDoc}
   */
  protected String getCommandLinePath()
  {
    return null;
  }
  /**
   * {@inheritDoc}
   */
  public void runTask()
  {
    try
    {
      updateSchema();
      state = State.FINISHED_SUCCESSFULLY;
    }
    catch (Throwable t)
    {
      // TODO
      //revertChanges();
      lastException = t;
      state = State.FINISHED_WITH_ERROR;
    }
  }
  private ObjectClass getObjectClassToAdd(ObjectClass ocToDelete)
  {
    ObjectClass ocToAdd;
    if (ocToDelete.equals(oldObjectClass))
    {
      ocToAdd = newObjectClass;
    }
    else if (oldObjectClass.equals(ocToDelete.getSuperiorClass()))
    {
      ArrayList<String> allNames = new ArrayList<String>();
      for (String str : ocToDelete.getNormalizedNames())
      {
        allNames.add(str);
      }
      Map<String, List<String>> extraProperties =
        DeleteSchemaElementsTask.cloneExtraProperties(ocToDelete);
      ocToAdd = new ObjectClass("",
          ocToDelete.getPrimaryName(),
          allNames,
          ocToDelete.getOID(),
          ocToDelete.getDescription(),
          newObjectClass,
          ocToDelete.getRequiredAttributes(),
          ocToDelete.getOptionalAttributes(),
          ocToDelete.getObjectClassType(),
          ocToDelete.isObsolete(),
          extraProperties);
    }
    else
    {
      // Nothing to be changed in the definition of the object class itself.
      ocToAdd = ocToDelete;
    }
    return ocToAdd;
  }
  /**
   * Updates the schema.
   * @throws OpenDsException if an error occurs.
   */
  private void updateSchema() throws OpenDsException
  {
    Schema schema = getInfo().getServerDescriptor().getSchema();
    ArrayList<ObjectClass> ocs = new ArrayList<ObjectClass>();
    ocs.add(oldObjectClass);
    LinkedHashSet<ObjectClass> ocsToDelete =
      DeleteSchemaElementsTask.getOrderedObjectClassesToDelete(ocs, schema);
    ArrayList<ObjectClass> lOcsToDelete =
      new ArrayList<ObjectClass>(ocsToDelete);
    LinkedHashSet<ObjectClass> ocsToAdd = new LinkedHashSet<ObjectClass>();
    for (int i = lOcsToDelete.size() - 1; i >= 0; i--)
    {
      ocsToAdd.add(getObjectClassToAdd(lOcsToDelete.get(i)));
    }
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(Utilities.applyFont(
              INFO_CTRL_PANEL_EXPLANATION_TO_MODIFY_OBJECTCLASS.get(
                  oldObjectClass.getNameOrOID())+"<br><br>",
                  ColorAndFontConstants.progressFont));
      }
    });
    DeleteSchemaElementsTask deleteTask =
      new DeleteSchemaElementsTask(getInfo(), getProgressDialog(), ocsToDelete,
          new LinkedHashSet<AttributeType>(0));
    deleteTask.runTask();
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>",
                ColorAndFontConstants.progressFont));
      }
    });
    NewSchemaElementsTask createTask =
      new NewSchemaElementsTask(getInfo(), getProgressDialog(), ocsToAdd,
          new LinkedHashSet<AttributeType>(0));
    createTask.runTask();
    notifyConfigurationElementCreated(newObjectClass);
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/task/NewSchemaElementsTask.java
New file
@@ -0,0 +1,824 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.task;
import static org.opends.messages.AdminToolMessages.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.swing.SwingUtilities;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
import org.opends.guitools.controlpanel.ui.ProgressDialog;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.quicksetup.util.Utils;
import org.opends.server.config.ConfigConstants;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.opends.server.types.CommonSchemaElements;
import org.opends.server.types.Entry;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OpenDsException;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
import org.opends.server.util.ServerConstants;
/**
 * An abstract class used to re-factor some code between the different tasks
 * that create elements in the schema.
 *
 */
public class NewSchemaElementsTask extends Task
{
  LinkedHashSet<ObjectClass> ocsToAdd = new LinkedHashSet<ObjectClass>();
  LinkedHashSet<AttributeType> attrsToAdd = new LinkedHashSet<AttributeType>();
  /**
   * Constructor of the task.
   * @param info the control panel information.
   * @param dlg the progress dialog where the task progress will be displayed.
   * @param ocsToAdd the object classes that must be created in order.
   * @param attrsToAdd the attributes that must be created in order.
   */
  public NewSchemaElementsTask(ControlPanelInfo info, ProgressDialog dlg,
      LinkedHashSet<ObjectClass> ocsToAdd,
      LinkedHashSet<AttributeType> attrsToAdd)
  {
    super(info, dlg);
    this.ocsToAdd.addAll(ocsToAdd);
    this.attrsToAdd.addAll(attrsToAdd);
  }
  /**
   * {@inheritDoc}
   */
  public Set<String> getBackends()
  {
    return Collections.emptySet();
  }
  /**
   * {@inheritDoc}
   */
  public boolean canLaunch(Task taskToBeLaunched,
      Collection<Message> incompatibilityReasons)
  {
    boolean canLaunch = true;
    if (state == State.RUNNING &&
        (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT ||
         taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT))
    {
      incompatibilityReasons.add(getIncompatibilityMessage(this,
            taskToBeLaunched));
      canLaunch = false;
    }
    return canLaunch;
  }
  /**
   * {@inheritDoc}
   */
  public void runTask()
  {
    state = State.RUNNING;
    lastException = null;
    try
    {
      updateSchema();
      state = State.FINISHED_SUCCESSFULLY;
    }
    catch (Throwable t)
    {
      lastException = t;
      state = State.FINISHED_WITH_ERROR;
    }
  }
  /**
   * {@inheritDoc}
   */
  public Type getType()
  {
    return Type.NEW_SCHEMA_ELEMENT;
  }
  /**
   * {@inheritDoc}
   */
  public Message getTaskDescription()
  {
    if (attrsToAdd.size() == 1 && ocsToAdd.isEmpty())
    {
      String attributeName = attrsToAdd.iterator().next().getNameOrOID();
      return INFO_CTRL_PANEL_NEW_ATTRIBUTE_TASK_DESCRIPTION.get(attributeName);
    }
    else if (ocsToAdd.size() == 1 && attrsToAdd.isEmpty())
    {
      String ocName = ocsToAdd.iterator().next().getNameOrOID();
      return INFO_CTRL_PANEL_NEW_OBJECTCLASS_TASK_DESCRIPTION.get(ocName);
    }
    else
    {
      ArrayList<String> attrNames = new ArrayList<String>();
      for (AttributeType attribute : attrsToAdd)
      {
        attrNames.add(attribute.getNameOrOID());
      }
      ArrayList<String> ocNames = new ArrayList<String>();
      for (ObjectClass oc : ocsToAdd)
      {
        ocNames.add(oc.getNameOrOID());
      }
      if (ocNames.isEmpty())
      {
        return INFO_CTRL_PANEL_NEW_ATTRIBUTES_TASK_DESCRIPTION.get(
            Utils.getStringFromCollection(attrNames, ", "));
      }
      else if (attrNames.isEmpty())
      {
        return INFO_CTRL_PANEL_NEW_OBJECTCLASSES_TASK_DESCRIPTION.get(
            Utils.getStringFromCollection(ocNames, ", "));
      }
      else
      {
        return INFO_CTRL_PANEL_NEW_SCHEMA_ELEMENTS_TASK_DESCRIPTION.get(
            Utils.getStringFromCollection(attrNames, ", "),
            Utils.getStringFromCollection(ocNames, ", "));
      }
    }
  }
  /**
   * Update the schema.
   * @throws OpenDsException if an error occurs.
   */
  private void updateSchema() throws OpenDsException
  {
    if (isServerRunning())
    {
      updateSchemaOnline();
    }
    else
    {
      updateSchemaOffline();
    }
  }
  /**
   * {@inheritDoc}
   */
  protected String getCommandLinePath()
  {
    return null;
  }
  /**
   * {@inheritDoc}
   */
  protected List<String> getCommandLineArguments()
  {
    return Collections.emptyList();
  }
  private void updateSchemaOnline() throws OpenDsException
  {
    // Add the schema elements one by one: we are not sure that the server
    // will handle the adds sequentially if we only send one modification.
    for (AttributeType attr : attrsToAdd)
    {
      addAttributeOnline(attr);
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>",
              ColorAndFontConstants.progressFont));
        }
      });
    }
    for (ObjectClass oc : ocsToAdd)
    {
      addObjectClassOnline(oc);
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>",
              ColorAndFontConstants.progressFont));
        }
      });
    }
  }
  private void updateSchemaOffline() throws OpenDsException
  {
    // Group the changes in the same schema file.
    LinkedHashMap<String, List<AttributeType>> hmAttrs =
      new LinkedHashMap<String, List<AttributeType>>();
    for (AttributeType attr : attrsToAdd)
    {
      String fileName = getFileName(attr);
      if (fileName == null)
      {
        fileName = "";
      }
      List<AttributeType> attrs = hmAttrs.get(fileName);
      if (attrs == null)
      {
        attrs = new ArrayList<AttributeType>();
        hmAttrs.put(fileName, attrs);
      }
      attrs.add(attr);
    }
    LinkedHashMap<String, List<ObjectClass>> hmOcs =
      new LinkedHashMap<String, List<ObjectClass>>();
    for (ObjectClass oc : ocsToAdd)
    {
      String fileName = getFileName(oc);
      if (fileName == null)
      {
        fileName = "";
      }
      List<ObjectClass> ocs = hmOcs.get(fileName);
      if (ocs == null)
      {
        ocs = new ArrayList<ObjectClass>();
        hmOcs.put(fileName, ocs);
      }
      ocs.add(oc);
    }
    LinkedHashSet<String> allFileNames = new LinkedHashSet<String>();
    allFileNames.addAll(hmAttrs.keySet());
    allFileNames.addAll(hmOcs.keySet());
    for (String fileName : allFileNames)
    {
      List<AttributeType> attrs = hmAttrs.get(fileName);
      List<ObjectClass> ocs = hmOcs.get(fileName);
      if (attrs == null)
      {
        attrs = Collections.emptyList();
      }
      if (ocs == null)
      {
        ocs = Collections.emptyList();
      }
      if (fileName.equals(""))
      {
        fileName = null;
      }
      updateSchemaOffline(fileName, attrs, ocs);
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>",
              ColorAndFontConstants.progressFont));
        }
      });
    }
  }
  private void addAttributeOnline(final AttributeType attribute)
  throws OpenDsException
  {
    SwingUtilities.invokeLater(new Runnable()
    {
      /**
       * {@inheritDoc}
       */
      public void run()
      {
        printEquivalentCommandLineToAddOnline(attribute);
        getProgressDialog().appendProgressHtml(
            Utilities.getProgressWithPoints(
                INFO_CTRL_PANEL_CREATING_ATTRIBUTE_PROGRESS.get(
                    attribute.getNameOrOID()),
                    ColorAndFontConstants.progressFont));
      }
    });
    try
    {
      BasicAttribute attr = new BasicAttribute(getAttributeName(attribute));
      attr.add(getValueOnline(attribute));
      ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE,
          attr);
      getInfo().getDirContext().modifyAttributes(
          ConfigConstants.DN_DEFAULT_SCHEMA_ROOT,
          new ModificationItem[]  { mod });
    }
    catch (NamingException ne)
    {
      throw new OnlineUpdateException(
          ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne.toString()), ne);
    }
    notifyConfigurationElementCreated(attribute);
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(
            Utilities.getProgressDone(ColorAndFontConstants.progressFont));
      }
    });
  }
  private void addObjectClassOnline(final ObjectClass objectClass)
  throws OpenDsException
  {
    SwingUtilities.invokeLater(new Runnable()
    {
      /**
       * {@inheritDoc}
       */
      public void run()
      {
        printEquivalentCommandLineToAddOnline(objectClass);
        getProgressDialog().appendProgressHtml(
            Utilities.getProgressWithPoints(
                INFO_CTRL_PANEL_CREATING_OBJECTCLASS_PROGRESS.get(
                    objectClass.getNameOrOID()),
                    ColorAndFontConstants.progressFont));
      }
    });
    try
    {
      BasicAttribute attr = new BasicAttribute(getAttributeName(objectClass));
      attr.add(getValueOnline(objectClass));
      ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE,
          attr);
      getInfo().getDirContext().modifyAttributes(
          ConfigConstants.DN_DEFAULT_SCHEMA_ROOT,
          new ModificationItem[]  { mod });
    }
    catch (NamingException ne)
    {
      throw new OnlineUpdateException(
          ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne.toString()), ne);
    }
    notifyConfigurationElementCreated(objectClass);
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(
            Utilities.getProgressDone(ColorAndFontConstants.progressFont));
      }
    });
  }
  private String getValueOnline(CommonSchemaElements element)
  {
    return element.toString();
  }
  private String getValueOffline(CommonSchemaElements element)
  {
    Iterable<String> previousValues =
      element.getExtraProperty(ServerConstants.SCHEMA_PROPERTY_FILENAME);
    element.setExtraProperty(ServerConstants.SCHEMA_PROPERTY_FILENAME,
        (String)null);
    String attributeWithoutFileDefinition = element.toString();
    if (previousValues != null)
    {
      ArrayList<String> vs = new ArrayList<String>();
      for (String s : previousValues)
      {
        vs.add(s);
      }
      if (!vs.isEmpty())
      {
        element.setExtraProperty(ServerConstants.SCHEMA_PROPERTY_FILENAME, vs);
      }
    }
    return attributeWithoutFileDefinition;
  }
  private void printEquivalentCommandLineToAddOnline(
      CommonSchemaElements element)
  {
    ArrayList<String> args = new ArrayList<String>();
    args.add("-a");
    args.addAll(getObfuscatedCommandLineArguments(
        getConnectionCommandLineArguments(true, true)));
    args.add(getNoPropertiesFileArgument());
    String equiv = getEquivalentCommandLine(getCommandLinePath("ldapmodify"),
        args);
    StringBuilder sb = new StringBuilder();
    Message msg;
    if (element instanceof AttributeType)
    {
      msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_ATTRIBUTE_ONLINE.get(
          element.getNameOrOID());
    }
    else
    {
      msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_OBJECTCLASS_ONLINE.get(
          element.getNameOrOID());
    }
    sb.append(msg+"<br><b>");
    sb.append(equiv);
    sb.append("<br>");
    sb.append("dn: cn=schema<br>");
    sb.append("changetype: modify<br>");
    sb.append("add: "+getAttributeName(element)+"<br>");
    sb.append(getAttributeName(element)+": "+getValueOnline(element));
    sb.append("</b><br><br>");
    getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(),
        ColorAndFontConstants.progressFont));
  }
  private String getAttributeName(CommonSchemaElements element)
  {
    if (element instanceof AttributeType)
    {
      return ConfigConstants.ATTR_ATTRIBUTE_TYPES;
    }
    else
    {
      return ConfigConstants.ATTR_OBJECTCLASSES;
    }
  }
  private String getFileName(CommonSchemaElements element)
  {
    String value = null;
    Iterable<String> vs =
      element.getExtraProperty(ServerConstants.SCHEMA_PROPERTY_FILENAME);
    if (vs != null)
    {
      if (vs.iterator().hasNext())
      {
        value = vs.iterator().next();
      }
    }
    return value;
  }
  private void updateSchemaOffline(String file,
      final List<AttributeType> attributes,
      final List<ObjectClass> objectClasses) throws OpenDsException
  {
    final boolean userSchema;
    final String fileName;
    if (file == null)
    {
      file = ConfigConstants.FILE_USER_SCHEMA_ELEMENTS;
      userSchema = true;
    }
    else
    {
      userSchema = false;
    }
    File f = new File(file);
    if (!f.isAbsolute())
    {
      f = new File(
        DirectoryServer.getEnvironmentConfig().getSchemaDirectory(userSchema),
        file);
    }
    fileName = f.getAbsolutePath();
    final boolean isSchemaFileDefined = isSchemaFileDefined(fileName);
    SwingUtilities.invokeLater(new Runnable()
    {
      /**
       * {@inheritDoc}
       */
      public void run()
      {
        printEquivalentCommandToAddOffline(fileName, isSchemaFileDefined,
            attributes, objectClasses);
        if (attributes.size() == 1 && objectClasses.isEmpty())
        {
          String attributeName = attributes.get(0).getNameOrOID();
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_CREATING_ATTRIBUTE_PROGRESS.get(
                      attributeName),
                      ColorAndFontConstants.progressFont));
        }
        else if (objectClasses.size() == 1 && attributes.isEmpty())
        {
          String ocName = objectClasses.get(0).getNameOrOID();
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_CREATING_OBJECTCLASS_PROGRESS.get(
                      ocName),
                      ColorAndFontConstants.progressFont));
        }
        else
        {
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_UPDATING_SCHEMA_FILE_PROGRESS.get(
                      fileName),
                      ColorAndFontConstants.progressFont));
        }
      }
    });
    updateSchemaFile(fileName, isSchemaFileDefined, attributes, objectClasses);
    for (AttributeType attr : attributes)
    {
      notifyConfigurationElementCreated(attr);
    }
    for (ObjectClass oc : objectClasses)
    {
      notifyConfigurationElementCreated(oc);
    }
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        getProgressDialog().appendProgressHtml(
            Utilities.getProgressDone(ColorAndFontConstants.progressFont));
      }
    });
  }
  private void printEquivalentCommandToAddOffline(String schemaFile,
      boolean isSchemaFileDefined,
      List<AttributeType> attributes,
      List<ObjectClass> objectClasses)
  {
    ArrayList<String> names = new ArrayList<String>();
    for (AttributeType attr : attributes)
    {
      names.add(attr.getNameOrOID());
    }
    for (ObjectClass oc : objectClasses)
    {
      names.add(oc.getNameOrOID());
    }
    if (isSchemaFileDefined)
    {
      StringBuilder sb = new StringBuilder();
      sb.append(
          INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ELEMENT_OFFLINE.get(
              Utils.getStringFromCollection(names, ", "),
              schemaFile)+"<br><b>");
      for (AttributeType attribute : attributes)
      {
        sb.append(
            getAttributeName(attribute)+": "+getValueOffline(attribute)+"<br>");
      }
      for (ObjectClass oc : objectClasses)
      {
        sb.append(getAttributeName(oc)+": "+getValueOffline(oc)+"<br>");
      }
      sb.append("</b><br><br>");
      getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(),
          ColorAndFontConstants.progressFont));
    }
    else
    {
      StringBuilder sb = new StringBuilder();
      sb.append(INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ENTRY_OFFLINE.get(
          Utils.getStringFromCollection(names, ", "),
              schemaFile)+"<br><b>");
      for (String line : getSchemaEntryLines())
      {
        sb.append(line);
        sb.append("<br>");
      }
      for (AttributeType attribute : attributes)
      {
        sb.append(
            getAttributeName(attribute)+": "+getValueOffline(attribute)+"<br>");
      }
      for (ObjectClass oc : objectClasses)
      {
        sb.append(getAttributeName(oc)+": "+getValueOffline(oc)+"<br>");
      }
      sb.append("</b><br><br>");
      getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(),
          ColorAndFontConstants.progressFont));
    }
  }
  /**
   * Returns whether the file defined in the schema element exists or not.
   * @param the path to the schema file.
   * @return <CODE>true</CODE> if the schema file is defined and
   * <CODE>false</CODE> otherwise.
   */
  private boolean isSchemaFileDefined(String schemaFile)
  {
    boolean schemaDefined = false;
    LDIFReader reader = null;
    try
    {
      reader = new LDIFReader(new LDIFImportConfig(schemaFile));
      Entry entry = reader.readEntry();
      if (entry != null)
      {
        schemaDefined = true;
      }
    }
    catch (Throwable t)
    {
    }
    finally
    {
      if (reader != null)
      {
        try
        {
          reader.close();
        }
        catch (Throwable t)
        {
        }
      }
    }
    return schemaDefined;
  }
  /**
   * Returns the list of LDIF lines that are enough to create the entry
   * containing only the schema element associated with this task.
   * @return the list of LDIF lines that are enough to create the entry
   * containing only the schema element associated with this task.
   */
  private ArrayList<String> getSchemaEntryLines()
  {
    ArrayList<String> lines = new ArrayList<String>();
    lines.add("dn: cn=schema");
    lines.add("objectClass: top");
    lines.add("objectClass: ldapSubentry");
    lines.add("objectClass: subschema");
    return lines;
  }
  /**
   * Updates the contents of the schema file.
   *
   * @param schemaFile the schema file.
   * @param isSchemaFileDefined whether the schema is defined or not.
   * @param attributes the attributes to add.
   * @param objectClasses the object classes to add.
   * @throws OpenDsException if an error occurs updating the schema file.
   */
  private void updateSchemaFile(String schemaFile,
      boolean isSchemaFileDefined,
      List<AttributeType> attributes,
      List<ObjectClass> objectClasses) throws OpenDsException
  {
    if (isSchemaFileDefined)
    {
      LDIFExportConfig exportConfig =
        new LDIFExportConfig(schemaFile,
                             ExistingFileBehavior.OVERWRITE);
      LDIFReader reader = null;
      Entry schemaEntry = null;
      try
      {
        reader = new LDIFReader(new LDIFImportConfig(schemaFile));
        schemaEntry = reader.readEntry();
        for (AttributeType attribute : attributes)
        {
          Modification mod = new Modification(ModificationType.ADD,
              Attributes.create(getAttributeName(attribute).toLowerCase(),
                  getValueOffline(attribute)));
          schemaEntry.applyModification(mod);
        }
        for (ObjectClass oc : objectClasses)
        {
          Modification mod = new Modification(ModificationType.ADD,
              Attributes.create(getAttributeName(oc).toLowerCase(),
                  getValueOffline(oc)));
          schemaEntry.applyModification(mod);
        }
        LDIFWriter writer = new LDIFWriter(exportConfig);
        writer.writeEntry(schemaEntry);
        exportConfig.getWriter().newLine();
      }
      catch (Throwable t)
      {
      }
      finally
      {
        if (reader != null)
        {
          try
          {
            reader.close();
          }
          catch (Throwable t)
          {
          }
        }
        if (exportConfig != null)
        {
          try
          {
            exportConfig.close();
          }
          catch (Throwable t)
          {
          }
        }
      }
    }
    else
    {
      LDIFExportConfig exportConfig =
        new LDIFExportConfig(schemaFile,
                             ExistingFileBehavior.FAIL);
      try
      {
        ArrayList<String> lines = getSchemaEntryLines();
        for (AttributeType attribute : attributes)
        {
          lines.add(
              getAttributeName(attribute)+": "+getValueOffline(attribute));
        }
        for (ObjectClass oc : objectClasses)
        {
          lines.add(getAttributeName(oc)+": "+getValueOffline(oc));
        }
        for (String line : lines)
        {
          LDIFWriter.writeLDIFLine(new StringBuilder(line),
              exportConfig.getWriter(), exportConfig.getWrapColumn() > 1,
              exportConfig.getWrapColumn());
        }
        exportConfig.getWriter().newLine();
      }
      catch (Throwable t)
      {
        throw new OfflineUpdateException(
            ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(t.toString()), t);
      }
      finally
      {
        if (exportConfig != null)
        {
          try
          {
            exportConfig.close();
          }
          catch (Throwable t)
          {
          }
        }
      }
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/task/SchemaTask.java
File was deleted
opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
@@ -45,6 +45,9 @@
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.ConfigurationElementCreatedEvent;
import org.opends.guitools.controlpanel.event.
 ConfigurationElementCreatedListener;
import org.opends.guitools.controlpanel.event.PrintStreamListener;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
import org.opends.guitools.controlpanel.ui.ProgressDialog;
@@ -150,21 +153,17 @@
     */
    JAVA_SETTINGS_UPDATE,
    /**
     * Creating a new attribute in the schema.
     * Creating a new element in the schema.
     */
    NEW_ATTRIBUTE,
    NEW_SCHEMA_ELEMENT,
    /**
     * Creating a new objectclass in the schema.
     * Deleting an schema element.
     */
    NEW_OBJECTCLASS,
    DELETE_SCHEMA_ELEMENT,
    /**
     * Deleting an attribute in the schema.
     * Modify an schema element.
     */
    DELETE_ATTRIBUTE,
    /**
     * Deleting an objectclass in the schema.
     */
    DELETE_OBJECTCLASS,
    MODIFY_SCHEMA_ELEMENT,
    /**
     * Modifying an entry.
     */
@@ -269,6 +268,9 @@
  private ProgressDialog progressDialog;
  private ArrayList<ConfigurationElementCreatedListener> confListeners =
    new ArrayList<ConfigurationElementCreatedListener>();
  private static int MAX_BINARY_LENGTH_TO_DISPLAY = 1024;
  /**
@@ -424,6 +426,40 @@
  public abstract Message getTaskDescription();
  /**
   * Adds a configuration element created listener.
   * @param listener the listener.
   */
  public void addConfigurationElementCreatedListener(
      ConfigurationElementCreatedListener listener)
  {
    confListeners.add(listener);
  }
  /**
   * Removes a configuration element created listener.
   * @param listener the listener.
   */
  public void removeConfigurationElementCreatedListener(
      ConfigurationElementCreatedListener listener)
  {
    confListeners.remove(listener);
  }
  /**
   * Notifies the configuration element created listener that a new object has
   * been created.
   * @param configObject the created object.
   */
  protected void notifyConfigurationElementCreated(Object configObject)
  {
    for (ConfigurationElementCreatedListener listener : confListeners)
    {
      listener.elementCreated(
          new ConfigurationElementCreatedEvent(this, configObject));
    }
  }
  /**
   * Returns a String representation of a value.  In general this is called
   * to display the command-line equivalent when we do a modification in an
   * entry.  But since some attributes must be obfuscated (like the user
opends/src/guitools/org/opends/guitools/controlpanel/ui/BrowseSchemaPanel.java
@@ -44,6 +44,7 @@
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
@@ -86,6 +87,7 @@
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.guitools.controlpanel.util.ViewPositions;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.MatchingRule;
import org.opends.server.types.AttributeType;
@@ -518,6 +520,14 @@
        selectElementUnder(root, element, model);
      }
    });
    entryPane.addConfigurationElementCreatedListener(
        new ConfigurationElementCreatedListener()
        {
          public void elementCreated(ConfigurationElementCreatedEvent ev)
          {
            configurationElementCreated(ev);
          }
        });
    treePane.getTree().addTreeSelectionListener(new TreeSelectionListener()
    {
@@ -632,22 +642,40 @@
  {
    final ServerDescriptor desc = ev.getNewDescriptor();
    final boolean forceScroll = lastSchema == null;
    if ((lastSchema == null) ||
        !ServerDescriptor.areSchemasEqual(lastSchema, desc.getSchema())||
        true)
    Schema schema = desc.getSchema();
    boolean schemaChanged;
    if (schema != null && lastSchema != null)
    {
      lastSchema = desc.getSchema();
      if (lastSchema != null)
      schemaChanged = !ServerDescriptor.areSchemasEqual(lastSchema, schema);
    }
    else if (schema == null && lastSchema != null)
      {
      schemaChanged = false;
    }
    else if (lastSchema == null && schema != null)
    {
      schemaChanged = true;
    }
    else
    {
      schemaChanged = false;
    }
    if (schemaChanged)
    {
      lastSchema = schema;
        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            repopulateTree(treePane.getTree(), forceScroll);
          if (errorPane.isVisible())
          {
            errorPane.setVisible(false);
          }
          }
        });
      }
      else
    else if (lastSchema == null)
      {
        updateErrorPane(errorPane,
            ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_SUMMARY.get(),
@@ -660,7 +688,6 @@
        }
      }
    }
  }
  /**
   * Selects the node in the tree that corresponds to a given schema element.
@@ -1099,8 +1126,8 @@
      }
      else if (node instanceof CustomObjectClassTreeNode)
      {
        entryPane.updateCustomObjectClass(
            ((CustomObjectClassTreeNode)node).getObjectClass(), lastSchema);
        ObjectClass oc = ((CustomObjectClassTreeNode)node).getObjectClass();
        entryPane.updateCustomObjectClass(oc, lastSchema);
      }
      else if (node instanceof StandardAttributeTreeNode)
      {
@@ -1114,8 +1141,8 @@
      }
      else if (node instanceof CustomAttributeTreeNode)
      {
        entryPane.updateCustomAttribute(
            ((CustomAttributeTreeNode)node).getAttribute(), lastSchema);
        AttributeType attr = ((CustomAttributeTreeNode)node).getAttribute();
        entryPane.updateCustomAttribute(attr, lastSchema);
      }
      else if (node instanceof MatchingRuleTreeNode)
      {
@@ -1248,146 +1275,20 @@
    }
    Schema schema = getInfo().getServerDescriptor().getSchema();
    ArrayList<String> ocNames = new ArrayList<String>();
    ArrayList<String> attrNames = new ArrayList<String>();
    if (schema != null)
    {
//    Analyze objectClasses
      for (ObjectClass objectClass : ocsToDelete)
      {
        ArrayList<ObjectClass> childClasses = new ArrayList<ObjectClass>();
        for (ObjectClass o : schema.getObjectClasses().values())
        {
          if (objectClass.equals(o.getSuperiorClass()))
          {
            childClasses.add(o);
          }
        }
        childClasses.removeAll(ocsToDelete);
        if (!childClasses.isEmpty())
        {
          ArrayList<String> childNames = new ArrayList<String>();
          for (ObjectClass oc : childClasses)
          {
            childNames.add(oc.getNameOrOID());
          }
          String ocName = objectClass.getNameOrOID();
          errors.add(ERR_CANNOT_DELETE_PARENT_OBJECTCLASS.get(ocName,
              Utilities.getStringFromCollection(childNames, ", "), ocName));
        }
        ocNames.add(objectClass.getNameOrOID());
      }
//    Analyze attributes
      for (AttributeType attribute : attrsToDelete)
      {
        String attrName = attribute.getNameOrOID();
        ArrayList<AttributeType> childAttributes =
          new ArrayList<AttributeType>();
        for (AttributeType attr : schema.getAttributeTypes().values())
        {
          if (attribute.equals(attr.getSuperiorType()))
          {
            childAttributes.add(attr);
          }
        }
        childAttributes.removeAll(attrsToDelete);
        if (!childAttributes.isEmpty())
        {
          ArrayList<String> childNames = new ArrayList<String>();
          for (AttributeType attr : childAttributes)
          {
            childNames.add(attr.getNameOrOID());
          }
          errors.add(ERR_CANNOT_DELETE_PARENT_ATTRIBUTE.get(attrName,
              Utilities.getStringFromCollection(childNames, ", "), attrName));
        }
        ArrayList<String> dependentClasses = new ArrayList<String>();
        for (ObjectClass o : schema.getObjectClasses().values())
        {
          if (o.getRequiredAttributeChain().contains(attribute))
          {
            dependentClasses.add(o.getNameOrOID());
          }
        }
        dependentClasses.removeAll(ocsToDelete);
        if (!dependentClasses.isEmpty())
        {
          errors.add(ERR_CANNOT_DELETE_ATTRIBUTE_WITH_DEPENDENCIES.get(
              attrName,
              Utilities.getStringFromCollection(dependentClasses, ", "),
              attrName));
        }
        attrNames.add(attribute.getNameOrOID());
      }
    }
    else
    if (schema == null)
    {
      errors.add(ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get());
    }
    if (errors.isEmpty())
    {
      // Reorder objectClasses and attributes to delete them in the proper
      // order.
      ArrayList<ObjectClass> orderedObjectClasses =
        new ArrayList<ObjectClass>();
      for (ObjectClass oc : ocsToDelete)
      {
        int index = -1;
        for (int i=0; i<orderedObjectClasses.size(); i++)
        {
          ObjectClass parent = orderedObjectClasses.get(i).getSuperiorClass();
          while ((parent != null) && (index == -1))
          {
            if (parent.equals(oc))
            {
              index = i+1;
            }
            else
            {
              parent = parent.getSuperiorClass();
            }
          }
        }
        if (index == -1)
        {
          orderedObjectClasses.add(oc);
        }
        else
        {
          orderedObjectClasses.add(index, oc);
        }
      }
      Message confirmationMessage =
        getConfirmationMessage(ocsToDelete, attrsToDelete, schema);
      ArrayList<AttributeType> orderedAttributes =
        new ArrayList<AttributeType>();
      for (AttributeType attr : attrsToDelete)
      {
        int index = -1;
        for (int i=0; i<orderedAttributes.size(); i++)
        {
          AttributeType parent = orderedAttributes.get(i).getSuperiorType();
          while ((parent != null) && (index == -1))
          {
            if (parent.equals(attr))
            {
              index = i+1;
            }
            else
            {
              parent = parent.getSuperiorType();
            }
          }
        }
        if (index == -1)
        {
          orderedAttributes.add(attr);
        }
        else
        {
          orderedAttributes.add(index, attr);
        }
      }
      LinkedHashSet<AttributeType> orderedAttributes =
        getOrderedAttributesToDelete(attrsToDelete);
      LinkedHashSet<ObjectClass> orderedObjectClasses =
        getOrderedObjectClassesToDelete(ocsToDelete);
      Message title;
      if (orderedAttributes.isEmpty())
      {
@@ -1414,11 +1315,6 @@
      if (errors.isEmpty())
      {
        ArrayList<String> allNames = new ArrayList<String>();
        allNames.addAll(ocNames);
        allNames.addAll(attrNames);
        Message confirmationMessage =
          INFO_CTRL_PANEL_CONFIRMATION_DELETE_SCHEMA_ELEMENTS_DETAILS.get(
          Utilities.getStringFromCollection(allNames, ", "));
        if (displayConfirmationDialog(
            INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
            confirmationMessage))
@@ -1749,11 +1645,7 @@
          {
            public void elementCreated(ConfigurationElementCreatedEvent ev)
            {
              Object o = ev.getConfigurationObject();
              if (o instanceof CommonSchemaElements)
              {
                lastCreatedElement = (CommonSchemaElements)o;
              }
              configurationElementCreated(ev);
            }
          });
    }
@@ -1775,16 +1667,21 @@
          {
            public void elementCreated(ConfigurationElementCreatedEvent ev)
            {
              configurationElementCreated(ev);
            }
          });
    }
    newObjectClassDialog.setVisible(true);
  }
  private void configurationElementCreated(ConfigurationElementCreatedEvent ev)
  {
              Object o = ev.getConfigurationObject();
              if (o instanceof CommonSchemaElements)
              {
                lastCreatedElement = (CommonSchemaElements)o;
              }
            }
          });
    }
    newObjectClassDialog.setVisible(true);
  }
  private HashMap<Object, ImageIcon> hmCategoryImages =
    new HashMap<Object, ImageIcon>();
@@ -1850,4 +1747,198 @@
      return icon;
    }
  }
  private LinkedHashSet<ObjectClass> getOrderedObjectClassesToDelete(
      Collection<ObjectClass> ocsToDelete)
  {
    ArrayList<ObjectClass> lOrderedOcs = new ArrayList<ObjectClass>();
    // Reorder objectClasses and attributes to delete them in the proper
    // order.
    for (ObjectClass oc : ocsToDelete)
    {
      int index = -1;
      for (int i=0; i<lOrderedOcs.size(); i++)
      {
        ObjectClass parent = lOrderedOcs.get(i).getSuperiorClass();
        while ((parent != null) && (index == -1))
        {
          if (parent.equals(oc))
          {
            index = i+1;
          }
          else
          {
            parent = parent.getSuperiorClass();
          }
        }
      }
      if (index == -1)
      {
        lOrderedOcs.add(oc);
      }
      else
      {
        lOrderedOcs.add(index, oc);
      }
    }
    return new LinkedHashSet<ObjectClass>(lOrderedOcs);
  }
  private LinkedHashSet<AttributeType> getOrderedAttributesToDelete(
      Collection<AttributeType> attrsToDelete)
  {
    ArrayList<AttributeType> lOrderedAttributes =
      new ArrayList<AttributeType>();
    for (AttributeType attr : attrsToDelete)
    {
      int index = -1;
      for (int i=0; i<lOrderedAttributes.size(); i++)
      {
        AttributeType parent = lOrderedAttributes.get(i).getSuperiorType();
        while ((parent != null) && (index == -1))
        {
          if (parent.equals(attr))
          {
            index = i+1;
          }
          else
          {
            parent = parent.getSuperiorType();
          }
        }
      }
      if (index == -1)
      {
        lOrderedAttributes.add(attr);
      }
      else
      {
        lOrderedAttributes.add(index, attr);
      }
    }
    return new LinkedHashSet<AttributeType>(lOrderedAttributes);
  }
  private Message getConfirmationMessage(
      Collection<ObjectClass> ocsToDelete,
      Collection<AttributeType> attrsToDelete,
      Schema schema)
  {
    ArrayList<ObjectClass> childClasses = new ArrayList<ObjectClass>();
    // Analyze objectClasses
    for (ObjectClass objectClass : ocsToDelete)
    {
      for (ObjectClass o : schema.getObjectClasses().values())
      {
        if (objectClass.equals(o.getSuperiorClass()))
        {
          childClasses.add(o);
        }
      }
      childClasses.removeAll(ocsToDelete);
    }
    ArrayList<AttributeType> childAttributes = new ArrayList<AttributeType>();
    TreeSet<String> dependentClasses = new TreeSet<String>();
    // Analyze attributes
    for (AttributeType attribute : attrsToDelete)
    {
      for (AttributeType attr : schema.getAttributeTypes().values())
      {
        if (attribute.equals(attr.getSuperiorType()))
        {
          childAttributes.add(attr);
        }
      }
      childAttributes.removeAll(attrsToDelete);
      for (ObjectClass o : schema.getObjectClasses().values())
      {
        if (o.getRequiredAttributeChain().contains(attribute))
        {
          dependentClasses.add(o.getNameOrOID());
        }
        else if (o.getOptionalAttributeChain().contains(attribute))
        {
          dependentClasses.add(o.getNameOrOID());
        }
      }
      for (ObjectClass oc : ocsToDelete)
      {
        dependentClasses.remove(oc.getNameOrOID());
      }
    }
    MessageBuilder mb = new MessageBuilder();
    if (!childClasses.isEmpty())
    {
      TreeSet<String> childNames = new TreeSet<String>();
      for (ObjectClass oc : childClasses)
      {
        childNames.add(oc.getNameOrOID());
      }
      if (ocsToDelete.size() == 1)
      {
        mb.append(INFO_OBJECTCLASS_IS_SUPERIOR.get(
            ocsToDelete.iterator().next().getNameOrOID(),
            Utilities.getStringFromCollection(childNames, ", ")));
      }
      else
      {
        mb.append(INFO_OBJECTCLASSES_ARE_SUPERIOR.get(
            Utilities.getStringFromCollection(childNames, ", ")));
      }
      mb.append("<br>");
    }
    if (!childAttributes.isEmpty())
    {
      TreeSet<String> childNames = new TreeSet<String>();
      for (AttributeType attr : childAttributes)
      {
        childNames.add(attr.getNameOrOID());
      }
      if (attrsToDelete.size() == 1)
      {
        mb.append(INFO_ATTRIBUTE_IS_SUPERIOR.get(
            attrsToDelete.iterator().next().getNameOrOID(),
            Utilities.getStringFromCollection(childNames, ", ")));
      }
      else
      {
        mb.append(INFO_ATTRIBUTES_ARE_SUPERIOR.get(
            Utilities.getStringFromCollection(childNames, ", ")));
      }
      mb.append("<br>");
    }
    if (!dependentClasses.isEmpty())
    {
      if (attrsToDelete.size() == 1)
      {
        mb.append(INFO_ATTRIBUTE_WITH_DEPENDENCIES.get(
            attrsToDelete.iterator().next().getNameOrOID(),
            Utilities.getStringFromCollection(dependentClasses, ", ")));
      }
      else
      {
        mb.append(INFO_ATTRIBUTES_WITH_DEPENDENCIES.get(
            Utilities.getStringFromCollection(dependentClasses, ", ")));
      }
      mb.append("<br>");
    }
    ArrayList<String> allNames = new ArrayList<String>();
    for (ObjectClass ocToDelete : ocsToDelete)
    {
      allNames.add(ocToDelete.getNameOrOID());
    }
    for (AttributeType attrToDelete : attrsToDelete)
    {
      allNames.add(attrToDelete.getNameOrOID());
    }
    Message confirmationMessage =
      INFO_CTRL_PANEL_CONFIRMATION_DELETE_SCHEMA_ELEMENTS_MSG.get(
          Utilities.getStringFromCollection(allNames, ", "));
    mb.append(confirmationMessage);
    return mb.toMessage();
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/CustomAttributePanel.java
@@ -29,41 +29,168 @@
import static org.opends.messages.AdminToolMessages.*;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.event.
 ConfigurationElementCreatedListener;
import org.opends.guitools.controlpanel.event.ScrollPaneBorderListener;
import org.opends.guitools.controlpanel.task.DeleteSchemaElementsTask;
import org.opends.guitools.controlpanel.task.ModifyAttributeTask;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.components.BasicExpander;
import org.opends.guitools.controlpanel.ui.components.TitlePanel;
import org.opends.guitools.controlpanel.ui.renderer.
 SchemaElementComboBoxCellRenderer;
import org.opends.guitools.controlpanel.util.LowerCaseComparator;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.MatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeUsage;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.Schema;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
/**
 * The panel that displays a custom attribute definition.
 *
 */
public class CustomAttributePanel extends StandardAttributePanel
public class CustomAttributePanel extends SchemaElementPanel
{
  private static final long serialVersionUID = 2850763193735843746L;
  private JButton delete;
  private JButton saveChanges;
  private AttributeType attribute;
  private String attrName;
  private ScrollPaneBorderListener scrollListener;
  private TitlePanel titlePanel = new TitlePanel(Message.EMPTY,
      Message.EMPTY);
  private JLabel lName = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_NAME_LABEL.get());
  private JLabel lSuperior = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_PARENT_LABEL.get());
  private JLabel lOID = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_OID_LABEL.get());
  private JLabel lAliases = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_ALIASES_LABEL.get());
  private JLabel lOrigin = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_ORIGIN_LABEL.get());
  private JLabel lFile = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_FILE_LABEL.get());
  private JLabel lDescription = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_DESCRIPTION_LABEL.get());
  private JLabel lUsage = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_USAGE_LABEL.get());
  private JLabel lSyntax = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_SYNTAX_LABEL.get());
  private JLabel lApproximate = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_APPROXIMATE_MATCHING_RULE_LABEL.get());
  private JLabel lEquality = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_EQUALITY_MATCHING_RULE_LABEL.get());
  private JLabel lOrdering = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_ORDERING_MATCHING_RULE_LABEL.get());
  private JLabel lSubstring = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_ATTRIBUTE_SUBSTRING_MATCHING_RULE_LABEL.get());
  private JLabel lType = Utilities.createPrimaryLabel();
  private JLabel[] labels = {lName, lSuperior, lOID, lAliases, lOrigin, lFile,
      lDescription, lUsage, lSyntax, lApproximate,
      lEquality, lOrdering, lSubstring, lType
  };
  private JTextField name = Utilities.createMediumTextField();
  private JComboBox parent = Utilities.createComboBox();
  private JTextField oid = Utilities.createMediumTextField();
  private JTextField aliases = Utilities.createLongTextField();
  private JTextField description = Utilities.createLongTextField();
  private JTextField origin = Utilities.createLongTextField();
  private JTextField file = Utilities.createLongTextField();
  private JComboBox usage = Utilities.createComboBox();
  private JComboBox syntax = Utilities.createComboBox();
  private JComboBox approximate = Utilities.createComboBox();
  private JComboBox equality = Utilities.createComboBox();
  private JComboBox ordering = Utilities.createComboBox();
  private JComboBox substring = Utilities.createComboBox();
  private JCheckBox nonModifiable = Utilities.createCheckBox(
      INFO_CTRL_PANEL_ATTRIBUTE_NON_MODIFIABLE_LABEL.get());
  private JCheckBox singleValued = Utilities.createCheckBox(
      INFO_CTRL_PANEL_ATTRIBUTE_SINGLE_VALUED_LABEL.get());
  private JCheckBox collective = Utilities.createCheckBox(
      INFO_CTRL_PANEL_ATTRIBUTE_COLLECTIVE_LABEL.get());
  private JCheckBox obsolete = Utilities.createCheckBox(
      INFO_CTRL_PANEL_ATTRIBUTE_OBSOLETE_LABEL.get());
  private JList requiredBy = new JList(new DefaultListModel());
  private JList optionalBy = new JList(new DefaultListModel());
  private Set<String> lastAliases = new LinkedHashSet<String>();
  private Message NO_PARENT = INFO_CTRL_PANEL_NO_PARENT_FOR_ATTRIBUTE.get();
  private Message NO_MATCHING_RULE =
    INFO_CTRL_PANEL_NO_MATCHING_RULE_FOR_ATTRIBUTE.get();
  private Schema schema;
  private boolean ignoreChangeEvents;
  /**
   * Default constructor of the panel.
   *
   */
  public CustomAttributePanel()
  {
    super();
    createLayout();
  }
  /**
   * {@inheritDoc}
   */
@@ -81,10 +208,11 @@
    JPanel p = new JPanel(new GridBagLayout());
    p.setOpaque(false);
    p.setBorder(PANEL_BORDER);
    super.createBasicLayout(p, gbc);
    createBasicLayout(p, gbc);
    gbc = new GridBagConstraints();
    gbc.weightx = 1.0;
    gbc.weighty = 1.0;
    gbc.gridwidth = 2;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.gridx = 0;
    gbc.gridy = 0;
@@ -98,6 +226,7 @@
    gbc.anchor = GridBagConstraints.WEST;
    gbc.fill = GridBagConstraints.NONE;
    gbc.insets = new Insets(10, 10, 10, 10);
    gbc.gridwidth = 1;
    delete = Utilities.createButton(
        INFO_CTRL_PANEL_DELETE_ATTRIBUTE_BUTTON.get());
    delete.setOpaque(false);
@@ -112,6 +241,325 @@
        deleteAttribute();
      }
    });
    gbc.anchor = GridBagConstraints.EAST;
    gbc.gridx ++;
    saveChanges =
      Utilities.createButton(INFO_CTRL_PANEL_SAVE_CHANGES_LABEL.get());
    saveChanges.setOpaque(false);
    add(saveChanges, gbc);
    saveChanges.addActionListener(new ActionListener()
    {
      /**
       * {@inheritDoc}
       */
      public void actionPerformed(ActionEvent ev)
      {
        ArrayList<Message> errors = new ArrayList<Message>();
        saveChanges(false, errors);
      }
    });
  }
  /**
   * Creates the basic layout of the panel.
   * @param c the container where all the components will be layed out.
   * @param gbc the grid bag constraints.
   */
  protected void createBasicLayout(Container c, GridBagConstraints gbc)
  {
    requiredBy.setVisibleRowCount(5);
    optionalBy.setVisibleRowCount(9);
    gbc.gridy = 0;
    gbc.gridwidth = 2;
    addErrorPane(c, gbc);
    gbc.gridy ++;
    gbc.anchor = GridBagConstraints.WEST;
    titlePanel.setTitle(INFO_CTRL_PANEL_ATTRIBUTE_DETAILS.get());
    gbc.fill = GridBagConstraints.NONE;
    gbc.insets.top = 5;
    gbc.insets.bottom = 7;
    c.add(titlePanel, gbc);
    gbc.insets.bottom = 0;
    gbc.insets.top = 8;
    gbc.gridy ++;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    JComboBox[] comboBoxes = {parent, syntax, approximate,
        equality, ordering, substring};
    Message[] defaultValues = {NO_PARENT, Message.EMPTY, NO_MATCHING_RULE,
        NO_MATCHING_RULE, NO_MATCHING_RULE, NO_MATCHING_RULE
    };
    SchemaElementComboBoxCellRenderer renderer = new
    SchemaElementComboBoxCellRenderer(syntax);
    for (int i=0; i<comboBoxes.length; i++)
    {
      DefaultComboBoxModel model = new DefaultComboBoxModel(
          new Object[]{defaultValues[i]});
      comboBoxes[i].setModel(model);
      comboBoxes[i].setRenderer(renderer);
    }
    DefaultComboBoxModel model = new DefaultComboBoxModel();
    for (AttributeUsage us : AttributeUsage.values())
    {
      model.addElement(us);
    }
    usage.setModel(model);
    usage.setSelectedItem(AttributeUsage.USER_APPLICATIONS);
    usage.setRenderer(renderer);
    Component[] basicComps = {name, oid, description,
        syntax};
    JLabel[] basicLabels = {lName, lOID, lDescription, lSyntax};
    JLabel[] basicInlineHelp = new JLabel[] {null, null, null,
        Utilities.createInlineHelpLabel(
            INFO_CTRL_PANEL_SYNTAX_INLINE_HELP.get())};
    add(basicLabels, basicComps, basicInlineHelp, c, gbc);
    BasicExpander[] expanders = new BasicExpander[] {
        new BasicExpander(INFO_CTRL_PANEL_EXTRA_OPTIONS_EXPANDER.get()),
        new BasicExpander(
            INFO_CTRL_PANEL_ATTRIBUTE_TYPE_OPTIONS_EXPANDER.get()),
        new BasicExpander(INFO_CTRL_PANEL_MATCHING_RULE_OPTIONS_EXPANDER.get())
    };
    Component[][] comps = {{parent, aliases, origin, file},
        {usage, singleValued, nonModifiable, collective, obsolete},
        {approximate, equality, ordering, substring}};
    JLabel[][] labels = {{lSuperior, lAliases, lOrigin, lFile},
        {lUsage, lType, null, null, null},
        {lApproximate, lEquality, lOrdering, lSubstring}};
    JLabel[][] inlineHelps = {{null,
      Utilities.createInlineHelpLabel(
          INFO_CTRL_PANEL_SEPARATED_WITH_COMMAS_HELP.get()), null,
      Utilities.createInlineHelpLabel(
          INFO_CTRL_PANEL_SCHEMA_FILE_ATTRIBUTE_HELP.get(File.separator))},
      {null, null, null, null, null, null},
      {Utilities.createInlineHelpLabel(
          INFO_CTRL_PANEL_MATCHING_RULE_APPROXIMATE_HELP.get()),
        Utilities.createInlineHelpLabel(
            INFO_CTRL_PANEL_MATCHING_RULE_EQUALITY_HELP.get()),
        Utilities.createInlineHelpLabel(
            INFO_CTRL_PANEL_MATCHING_RULE_ORDERING_HELP.get()),
        Utilities.createInlineHelpLabel(
            INFO_CTRL_PANEL_MATCHING_RULE_SUBSTRING_HELP.get())
      }
    };
    for (int i=0; i<expanders.length; i++)
    {
      gbc.gridwidth = 2;
      gbc.gridx = 0;
      gbc.insets.left = 0;
      c.add(expanders[i], gbc);
      final JPanel p = new JPanel(new GridBagLayout());
      gbc.insets.left = 15;
      gbc.gridy ++;
      c.add(p, gbc);
      gbc.gridy ++;
      p.setOpaque(false);
      GridBagConstraints gbc1 = new GridBagConstraints();
      gbc1.fill = GridBagConstraints.HORIZONTAL;
      gbc1.gridy = 0;
      add(labels[i], comps[i], inlineHelps[i], p, gbc1);
      final BasicExpander expander = expanders[i];
      ChangeListener changeListener = new ChangeListener()
      {
        /**
         * {@inheritDoc}
         */
        public void stateChanged(ChangeEvent e)
        {
          p.setVisible(expander.isSelected());
        }
      };
      expander.addChangeListener(changeListener);
      expander.setSelected(false);
      changeListener.stateChanged(null);
    }
    ItemListener itemListener = new ItemListener()
    {
      /**
       * {@inheritDoc}
       */
      public void itemStateChanged(ItemEvent ev)
      {
        if (ev.getStateChange() == ItemEvent.SELECTED)
        {
          updateDefaultMatchingRuleNames();
          approximate.setSelectedIndex(0);
          substring.setSelectedIndex(0);
          equality.setSelectedIndex(0);
          ordering.setSelectedIndex(0);
        }
      }
    };
    syntax.addItemListener(itemListener);
    Message[] msgs = new Message[] {
        INFO_CTRL_PANEL_REQUIRED_BY_LABEL.get(),
        INFO_CTRL_PANEL_ALLOWED_BY_LABEL.get()
        };
    JList[] lists = {requiredBy, optionalBy};
    gbc.anchor = GridBagConstraints.NORTHWEST;
    for (int i=0; i<msgs.length; i++)
    {
      gbc.insets.left = 0;
      gbc.weightx = 0.0;
      gbc.gridx = 0;
      if (i == 0)
      {
        gbc.insets.top = 15;
      }
      else
      {
        gbc.insets.top = 10;
      }
      c.add(Utilities.createPrimaryLabel(msgs[i]), gbc);
      gbc.insets.left = 10;
      gbc.gridx = 1;
      if (i == 0)
      {
        gbc.weighty = 0.35;
      }
      else
      {
        gbc.weighty = 0.65;
      }
      gbc.weightx = 1.0;
      c.add(Utilities.createScrollPane(lists[i]), gbc);
      gbc.gridy ++;
      final JList list = lists[i];
      MouseAdapter clickListener = new MouseAdapter()
      {
        /**
         * {@inheritDoc}
         */
        public void mouseClicked(MouseEvent ev)
        {
          if (ev.getClickCount() == 1)
          {
            objectClassSelected(list);
          }
        }
      };
      list.addMouseListener(clickListener);
      KeyAdapter keyListener = new KeyAdapter()
      {
        /**
         * {@inheritDoc}
         */
        public void keyTyped(KeyEvent ev)
        {
          if ((ev.getKeyChar() == KeyEvent.VK_SPACE) ||
              (ev.getKeyChar() == KeyEvent.VK_ENTER))
          {
            objectClassSelected(list);
          }
        }
      };
      list.addKeyListener(keyListener);
    }
    DocumentListener docListener = new DocumentListener()
    {
      /**
       * {@inheritDoc}
       */
      public void insertUpdate(DocumentEvent ev)
      {
        checkEnableSaveChanges();
      }
      /**
       * {@inheritDoc}
       */
      public void removeUpdate(DocumentEvent ev)
      {
        checkEnableSaveChanges();
      }
      /**
       * {@inheritDoc}
       */
      public void changedUpdate(DocumentEvent arg0)
      {
        checkEnableSaveChanges();
      }
    };
    JTextField[] tfs = {name, description, oid, aliases, origin, file};
    for (JTextField tf : tfs)
    {
      tf.getDocument().addDocumentListener(docListener);
    }
    ActionListener actionListener = new ActionListener()
    {
      public void actionPerformed(ActionEvent ev)
      {
        checkEnableSaveChanges();
      }
    };
    JComboBox[] combos = {parent, usage, syntax, approximate, equality,
        ordering, substring};
    for (JComboBox combo : combos)
    {
      combo.addActionListener(actionListener);
    }
    JCheckBox[] checkBoxes = {nonModifiable, singleValued, collective,
        obsolete};
    for (JCheckBox cb : checkBoxes)
    {
      cb.addActionListener(actionListener);
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean mustCheckUnsavedChanges()
  {
    return saveChanges.isEnabled();
  }
  /**
   * {@inheritDoc}
   */
  public UnsavedChangesDialog.Result checkUnsavedChanges()
  {
    UnsavedChangesDialog.Result result;
    UnsavedChangesDialog unsavedChangesDlg = new UnsavedChangesDialog(
          Utilities.getParentDialog(this), getInfo());
    unsavedChangesDlg.setMessage(INFO_CTRL_PANEL_UNSAVED_CHANGES_SUMMARY.get(),
        INFO_CTRL_PANEL_UNSAVED_ATTRIBUTE_CHANGES_DETAILS.get(
           attribute.getNameOrOID()));
    Utilities.centerGoldenMean(unsavedChangesDlg,
          Utilities.getParentDialog(this));
    unsavedChangesDlg.setVisible(true);
    result = unsavedChangesDlg.getResult();
    if (result == UnsavedChangesDialog.Result.SAVE)
    {
      ArrayList<Message> errors = new ArrayList<Message>();
      saveChanges(true, errors);
      if (!errors.isEmpty())
      {
        result = UnsavedChangesDialog.Result.CANCEL;
      }
    }
    return result;
  }
  /**
@@ -127,11 +575,119 @@
   */
  public void update(AttributeType attr, Schema schema)
  {
    super.update(attr, schema);
    ignoreChangeEvents = true;
    String n = attr.getPrimaryName();
    if (n == null)
    {
      n = "";
    }
    titlePanel.setDetails(Message.raw(n));
    name.setText(n);
    oid.setText(attr.getOID());
    n = attr.getDescription();
    if (n == null)
    {
      n = "";
    }
    description.setText(n);
    syntax.setSelectedItem(attr.getSyntax());
    AttributeType superior = attr.getSuperiorType();
    if (superior == null)
    {
      parent.setSelectedItem(NO_PARENT);
    }
    else
    {
      parent.setSelectedItem(superior);
    }
    Set<String> aliases = getAliases(attr);
    lastAliases.clear();
    lastAliases.addAll(aliases);
    this.aliases.setText(Utilities.getStringFromCollection(aliases, ", "));
    String sOrigin = Utilities.getOrigin(attr);
    if (sOrigin == null)
    {
      sOrigin = "";
    }
    origin.setText(sOrigin);
    String sFile = attr.getSchemaFile();
    if (sFile == null)
    {
      sFile = "";
    }
    file.setText(sFile);
    usage.setSelectedItem(attr.getUsage());
    singleValued.setSelected(attr.isSingleValue());
    nonModifiable.setSelected(attr.isNoUserModification());
    collective.setSelected(attr.isCollective());
    obsolete.setSelected(attr.isObsolete());
    JComboBox[] matchingRules = {approximate, equality, ordering, substring};
    MatchingRule[] rules = {attr.getApproximateMatchingRule(),
        attr.getEqualityMatchingRule(), attr.getOrderingMatchingRule(),
        attr.getSubstringMatchingRule()
    };
    for (int i=0; i<matchingRules.length; i++)
    {
      if (rules[i] != null)
      {
        matchingRules[i].setSelectedItem(rules[i]);
      }
      else
      {
        matchingRules[i].setSelectedItem(NO_MATCHING_RULE);
      }
    }
    Comparator<String> lowerCaseComparator = new LowerCaseComparator();
    SortedSet<String> requiredByOcs = new TreeSet<String>(lowerCaseComparator);
    for (ObjectClass oc : schema.getObjectClasses().values())
    {
      if (oc.getRequiredAttributeChain().contains(attr))
      {
        requiredByOcs.add(oc.getNameOrOID());
      }
    }
    DefaultListModel model = (DefaultListModel)requiredBy.getModel();
    model.clear();
    for (String oc : requiredByOcs)
    {
      model.addElement(oc);
    }
    SortedSet<String> optionalByOcs = new TreeSet<String>(lowerCaseComparator);
    for (ObjectClass oc : schema.getObjectClasses().values())
    {
      if (oc.getOptionalAttributeChain().contains(attr))
      {
        optionalByOcs.add(oc.getNameOrOID());
      }
    }
    model = (DefaultListModel)optionalBy.getModel();
    model.clear();
    for (String oc : optionalByOcs)
    {
      model.addElement(oc);
    }
    attribute = attr;
    attrName = attribute.getNameOrOID();
    attrName = attr.getNameOrOID();
    scrollListener.updateBorder();
    for (JLabel label : labels)
    {
      setPrimaryValid(label);
    }
    saveChanges.setEnabled(false);
    ignoreChangeEvents = false;
  }
  /**
@@ -139,11 +695,146 @@
   */
  public void configurationChanged(ConfigurationChangeEvent ev)
  {
    ArrayList<AttributeSyntax<?>> newSyntaxes =
      new ArrayList<AttributeSyntax<?>>();
    final ServerDescriptor desc = ev.getNewDescriptor();
    Schema s = desc.getSchema();
    boolean schemaChanged;
    if (schema != null && s != null)
    {
      schemaChanged = !ServerDescriptor.areSchemasEqual(s, schema);
    }
    else if (schema == null && s != null)
    {
      schemaChanged = true;
    }
    else if (s == null && schema != null)
    {
      schemaChanged = false;
    }
    else
    {
      schemaChanged = false;
    }
    if (schemaChanged)
    {
      schema = s;
      HashMap<String, AttributeSyntax<?>> syntaxNameMap = new HashMap<String,
      AttributeSyntax<?>>();
      for (String key : schema.getSyntaxes().keySet())
      {
        AttributeSyntax<?> syntax = schema.getSyntax(key);
        String name = syntax.getSyntaxName();
        if (name == null)
        {
          name = syntax.getOID();
        }
        syntaxNameMap.put(name, syntax);
      }
      SortedSet<String> orderedKeys =
        new TreeSet<String>(syntaxNameMap.keySet());
      for (String key : orderedKeys)
      {
        newSyntaxes.add(syntaxNameMap.get(key));
      }
      updateComboBoxModel(newSyntaxes,
          ((DefaultComboBoxModel)syntax.getModel()));
      HashMap<String, AttributeType> attributeNameMap = new HashMap<String,
      AttributeType>();
      for (String key : schema.getAttributeTypes().keySet())
      {
        AttributeType attr = schema.getAttributeType(key);
        attributeNameMap.put(attr.getNameOrOID(), attr);
      }
      orderedKeys.clear();
      orderedKeys.addAll(attributeNameMap.keySet());
      ArrayList<Object> newParents = new ArrayList<Object>();
      for (String key : orderedKeys)
      {
        newParents.add(attributeNameMap.get(key));
      }
      newParents.add(0, NO_PARENT);
      updateComboBoxModel(newParents,
          ((DefaultComboBoxModel)parent.getModel()));
      ArrayList<MatchingRule> approximateElements =
        new ArrayList<MatchingRule>();
      ArrayList<MatchingRule> equalityElements = new ArrayList<MatchingRule>();
      ArrayList<MatchingRule> orderingElements = new ArrayList<MatchingRule>();
      ArrayList<MatchingRule> substringElements = new ArrayList<MatchingRule>();
      HashMap<String, MatchingRule> matchingRuleNameMap = new HashMap<String,
      MatchingRule>();
      for (String key : schema.getMatchingRules().keySet())
      {
        MatchingRule rule = schema.getMatchingRule(key);
        matchingRuleNameMap.put(rule.getNameOrOID(), rule);
      }
      orderedKeys.clear();
      orderedKeys.addAll(matchingRuleNameMap.keySet());
      for (String key : orderedKeys)
      {
        MatchingRule matchingRule = matchingRuleNameMap.get(key);
        if (matchingRule instanceof ApproximateMatchingRule)
        {
          approximateElements.add(matchingRule);
        }
        else if (matchingRule instanceof EqualityMatchingRule)
        {
          equalityElements.add(matchingRule);
        }
        else if (matchingRule instanceof OrderingMatchingRule)
        {
          orderingElements.add(matchingRule);
        }
        else if (matchingRule instanceof SubstringMatchingRule)
        {
          substringElements.add(matchingRule);
        }
      }
      JComboBox[] combos = {approximate, equality, ordering, substring};
      ArrayList<ArrayList<MatchingRule>> ruleNames =
        new ArrayList<ArrayList<MatchingRule>>();
      ruleNames.add(approximateElements);
      ruleNames.add(equalityElements);
      ruleNames.add(orderingElements);
      ruleNames.add(substringElements);
      for (int i=0; i<combos.length; i++)
      {
        DefaultComboBoxModel model = (DefaultComboBoxModel)combos[i].getModel();
        ArrayList<Object> el = new ArrayList<Object>();
        el.addAll(ruleNames.get(i));
        if (model.getSize() == 0)
        {
          el.add(0, NO_MATCHING_RULE);
        }
        else
        {
          el.add(0, model.getElementAt(0));
        }
        updateComboBoxModel(el, model);
      }
    }
    else if (schema == null)
    {
      updateErrorPane(errorPane,
          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_SUMMARY.get(),
          ColorAndFontConstants.errorTitleFont,
          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get(),
          ColorAndFontConstants.defaultFont);
    }
    if (schema != null)
    {
    updateErrorPaneIfAuthRequired(desc,
        isLocal() ?
        INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_ATTRIBUTE_DELETE.get() :
      INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname()));
    }
    SwingUtilities.invokeLater(new Runnable()
    {
      /**
@@ -151,32 +842,55 @@
       */
      public void run()
      {
        delete.setEnabled(!authenticationRequired(desc));
        delete.setEnabled(!authenticationRequired(desc) &&
            delete.isEnabled() &&
            schema != null);
        checkEnableSaveChanges();
        saveChanges.setEnabled(saveChanges.isEnabled() &&
            !authenticationRequired(desc) &&
            schema != null);
      }
    });
  }
  /**
   * {@inheritDoc}
   */
  public Component getPreferredFocusComponent()
  {
    return name;
  }
  /**
   * {@inheritDoc}
   */
  public void okClicked()
  {
  }
  private void deleteAttribute()
  {
    ArrayList<Message> errors = new ArrayList<Message>();
    Schema schema = getInfo().getServerDescriptor().getSchema();
    ProgressDialog dlg = new ProgressDialog(
        Utilities.createFrame(),
        Utilities.getParentDialog(this),
        INFO_CTRL_PANEL_DELETE_ATTRIBUTE_TITLE.get(), getInfo());
    ArrayList<ObjectClass> ocsToDelete = new ArrayList<ObjectClass>();
    ArrayList<AttributeType> attrsToDelete = new ArrayList<AttributeType>();
    LinkedHashSet<AttributeType> attrsToDelete =
      new LinkedHashSet<AttributeType>(1);
    attrsToDelete.add(attribute);
    DeleteSchemaElementsTask newTask = new DeleteSchemaElementsTask(getInfo(),
        dlg, ocsToDelete, attrsToDelete);
    Task newTask = new DeleteSchemaElementsTask(getInfo(), dlg,
        new LinkedHashSet<ObjectClass>(0), attrsToDelete);
    for (Task task : getInfo().getTasks())
    {
      task.canLaunch(newTask, errors);
    }
    Schema schema = getInfo().getServerDescriptor().getSchema();
    TreeSet<String> childAttributes = new TreeSet<String>();
    TreeSet<String> dependentClasses = new TreeSet<String>();
    if (schema != null)
    {
      ArrayList<String> childAttributes = new ArrayList<String>();
      for (AttributeType attr : schema.getAttributeTypes().values())
      {
        if (attribute.equals(attr.getSuperiorType()))
@@ -184,37 +898,48 @@
          childAttributes.add(attr.getNameOrOID());
        }
      }
      if (!childAttributes.isEmpty())
      {
        errors.add(ERR_CANNOT_DELETE_PARENT_ATTRIBUTE.get(attrName,
            Utilities.getStringFromCollection(childAttributes, ", "),
            attrName));
      }
      ArrayList<String> dependentClasses = new ArrayList<String>();
      for (ObjectClass o : schema.getObjectClasses().values())
      {
        if (o.getRequiredAttributeChain().contains(attribute))
        {
          dependentClasses.add(o.getNameOrOID());
        }
      }
      if (!dependentClasses.isEmpty())
        else if (o.getOptionalAttributeChain().contains(attribute))
      {
        errors.add(ERR_CANNOT_DELETE_ATTRIBUTE_WITH_DEPENDENCIES.get(
            attrName,
            Utilities.getStringFromCollection(dependentClasses, ", "),
            attrName));
          dependentClasses.add(o.getNameOrOID());
      }
    }
    }
    else
    {
      errors.add(ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get());
    }
    if (errors.size() == 0)
    {
      MessageBuilder mb = new MessageBuilder();
      if (!childAttributes.isEmpty())
      {
        mb.append(INFO_ATTRIBUTE_IS_SUPERIOR.get(attrName,
            Utilities.getStringFromCollection(childAttributes, ", ")));
        mb.append("<br>");
      }
      if (!dependentClasses.isEmpty())
      {
        mb.append(INFO_ATTRIBUTE_WITH_DEPENDENCIES.get(
            attrName,
            Utilities.getStringFromCollection(dependentClasses, ", ")));
        mb.append("<br>");
      }
      Message confirmationMessage =
        INFO_CTRL_PANEL_CONFIRMATION_DELETE_ATTRIBUTE_DETAILS.get(
            attribute.getNameOrOID());
      mb.append(confirmationMessage);
      if (displayConfirmationDialog(
          INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
          confirmationMessage))
          mb.toMessage()))
      {
        launchOperation(newTask,
            INFO_CTRL_PANEL_DELETING_ATTRIBUTE_SUMMARY.get(attrName),
@@ -232,4 +957,376 @@
      displayErrorDialog(errors);
    }
  }
  private void saveChanges(boolean modal, ArrayList<Message> errors)
  {
    // Check if the aliases or the name have changed
    for (JLabel label : labels)
    {
      setPrimaryValid(label);
    }
    String n = getAttributeName();
    MessageBuilder err = new MessageBuilder();
    if (n.length() == 0)
    {
      errors.add(ERR_CTRL_PANEL_ATTRIBUTE_NAME_REQUIRED.get());
      setPrimaryInvalid(lName);
    }
    else if (!n.equalsIgnoreCase(attribute.getNameOrOID()))
    {
      if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
      {
        errors.add(ERR_CTRL_PANEL_INVALID_ATTRIBUTE_NAME.get(err.toString()));
        setPrimaryInvalid(lName);
        err = new MessageBuilder();
      }
      else
      {
        Message elementType = NewAttributePanel.getSchemaElementType(n, schema);
        if (elementType != null)
        {
          errors.add(ERR_CTRL_PANEL_ATTRIBUTE_NAME_ALREADY_IN_USE.get(n,
              elementType.toString()));
          setPrimaryInvalid(lName);
        }
      }
    }
    n = oid.getText().trim();
    if (n.length() > 0 && !n.equalsIgnoreCase(attribute.getOID()))
    {
      if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
      {
        errors.add(ERR_CTRL_PANEL_OID_NOT_VALID.get(err.toString()));
        setPrimaryInvalid(lOID);
        err = new MessageBuilder();
      }
      else
      {
        Message elementType = NewAttributePanel.getSchemaElementType(n, schema);
        if (elementType != null)
        {
          errors.add(ERR_CTRL_PANEL_OID_ALREADY_IN_USE.get(n,
              elementType.toString()));
          setPrimaryInvalid(lOID);
        }
      }
    }
    Collection<String> aliases = getAliases();
    Collection<String> oldAliases = getAliases(attribute);
    if (!aliases.equals(oldAliases))
    {
      for (String alias : aliases)
      {
        if (alias.trim().length() == 0)
        {
          errors.add(ERR_CTRL_PANEL_EMPTY_ALIAS.get());
          setPrimaryInvalid(lAliases);
        }
        else
        {
          boolean notPreviouslyDefined = true;
          for (String oldAlias : oldAliases)
          {
            if (oldAlias.equalsIgnoreCase(alias))
            {
              notPreviouslyDefined = false;
              break;
            }
          }
          if (notPreviouslyDefined)
          {
            Message elementType =
              NewAttributePanel.getSchemaElementType(alias, schema);
            if (elementType != null)
            {
              errors.add(ERR_CTRL_PANEL_ALIAS_ALREADY_IN_USE.get(n,
                  elementType.toString()));
              setPrimaryInvalid(lAliases);
            }
          }
        }
      }
    }
    AttributeType superior = getSuperior();
    if (superior != null)
    {
      if (superior.getNameOrOID().equalsIgnoreCase(attribute.getNameOrOID()))
      {
        errors.add(ERR_CTRL_PANEL_ATTRIBUTE_CANNOT_BE_ITS_SUPERIOR.get());
        setPrimaryInvalid(lSuperior);
      }
      else
      {
        // Check whether this object class is defined as parent as the superior.
        superior = superior.getSuperiorType();
        while (superior != null)
        {
          if (superior.getNameOrOID().equalsIgnoreCase(
              attribute.getNameOrOID()))
          {
            errors.add(
                ERR_CTRL_PANEL_ATTRIBUTE_IS_SUPERIOR_OF_SUPERIOR.get(
                getSuperior().getNameOrOID()));
            setPrimaryInvalid(lSuperior);
            break;
          }
          superior = superior.getSuperiorType();
        }
      }
    }
    setPrimaryValid(lUsage);
    if (nonModifiable.isSelected())
    {
      if (AttributeUsage.USER_APPLICATIONS.equals(usage.getSelectedItem()))
      {
        errors.add(ERR_NON_MODIFIABLE_CANNOT_BE_USER_APPLICATIONS.get());
        setPrimaryInvalid(lUsage);
      }
    }
    if (errors.size() == 0)
    {
      ProgressDialog dlg = new ProgressDialog(
          Utilities.createFrame(),
          Utilities.getParentDialog(this),
          INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TITLE.get(), getInfo());
      ModifyAttributeTask newTask = new ModifyAttributeTask(getInfo(),
          dlg, attribute, getNewAttribute());
      for (ConfigurationElementCreatedListener listener :
        getConfigurationElementCreatedListeners())
      {
        newTask.addConfigurationElementCreatedListener(listener);
      }
      for (Task task : getInfo().getTasks())
      {
        task.canLaunch(newTask, errors);
      }
      if (errors.size() == 0)
      {
        launchOperation(newTask,
            INFO_CTRL_PANEL_MODIFYING_ATTRIBUTE_SUMMARY.get(attrName),
            INFO_CTRL_PANEL_MODIFYING_ATTRIBUTE_COMPLETE.get(),
            INFO_CTRL_PANEL_MODIFYING_ATTRIBUTE_SUCCESSFUL.get(attrName),
            ERR_CTRL_PANEL_MODIFYING_ATTRIBUTE_ERROR_SUMMARY.get(),
            ERR_CTRL_PANEL_MODIFYING_ATTRIBUTE_ERROR_DETAILS.get(attrName),
            null,
            dlg);
        dlg.setVisible(true);
      }
    }
    if (!errors.isEmpty())
    {
      displayErrorDialog(errors);
    }
  }
  private void checkEnableSaveChanges()
  {
    if (ignoreChangeEvents) return;
    boolean changed;
    if (attribute != null)
    {
      try
      {
        changed = !attribute.toString().equals(getNewAttribute().toString());
      }
      catch (Throwable t)
      {
        changed = true;
      }
    }
    else
    {
      changed = false;
    }
    saveChanges.setEnabled(changed);
  }
  private String getAttributeName()
  {
    return name.getText().trim();
  }
  private String getOID()
  {
    String o = oid.getText().trim();
    if (o.length() == 0)
    {
      o = getAttributeName()+"-oid";
    }
    return o;
  }
  private ArrayList<String> getAliases()
  {
    ArrayList<String> al = new ArrayList<String>();
    String s = aliases.getText().trim();
    if (s.length() > 0)
    {
      String[] a = s.split(",");
      for (String alias : a)
      {
        al.add(alias.trim());
      }
    }
    return al;
  }
  private ArrayList<String> getAllNames()
  {
    ArrayList<String> al = new ArrayList<String>();
    al.add(getAttributeName());
    al.addAll(getAliases());
    return al;
  }
  private AttributeType getSuperior()
  {
    Object o = parent.getSelectedItem();
    if (NO_PARENT.equals(o))
    {
      return null;
    }
    else
    {
      return (AttributeType)o;
    }
  }
  private ApproximateMatchingRule getApproximateMatchingRule()
  {
    if (approximate.getSelectedIndex() == 0)
    {
      return null;
    }
    else
    {
      return (ApproximateMatchingRule)approximate.getSelectedItem();
    }
  }
  private EqualityMatchingRule getEqualityMatchingRule()
  {
    if (equality.getSelectedIndex() == 0)
    {
      return null;
    }
    else
    {
      return (EqualityMatchingRule)equality.getSelectedItem();
    }
  }
  private SubstringMatchingRule getSubstringMatchingRule()
  {
    if (substring.getSelectedIndex() == 0)
    {
      return null;
    }
    else
    {
      return (SubstringMatchingRule)substring.getSelectedItem();
    }
  }
  private OrderingMatchingRule getOrderingMatchingRule()
  {
    if (ordering.getSelectedIndex() == 0)
    {
      return null;
    }
    else
    {
      return (OrderingMatchingRule)ordering.getSelectedItem();
    }
  }
  private Map<String, List<String>> getExtraProperties()
  {
    Map<String, List<String>> map = new HashMap<String, List<String>>();
    String f = file.getText().trim();
    if (f.length() > 0)
    {
      ArrayList<String> list = new ArrayList<String>();
      list.add(f);
      map.put(ServerConstants.SCHEMA_PROPERTY_FILENAME, list);
    }
    String or = origin.getText().trim();
    if (or.length() > 0)
    {
      ArrayList<String> list = new ArrayList<String>();
      list.add(or);
      map.put(ServerConstants.SCHEMA_PROPERTY_ORIGIN, list);
    }
    return map;
  }
  private String getDescription()
  {
    return description.getText().trim();
  }
  private AttributeType getNewAttribute()
  {
    AttributeType attr = new AttributeType("", getAttributeName(),
        getAllNames(),
        getOID(),
        getDescription(),
        getSuperior(),
        (AttributeSyntax<?>)syntax.getSelectedItem(),
        getApproximateMatchingRule(),
        getEqualityMatchingRule(),
        getOrderingMatchingRule(),
        getSubstringMatchingRule(),
        (AttributeUsage)usage.getSelectedItem(),
        collective.isSelected(), nonModifiable.isSelected(),
        obsolete.isSelected(), singleValued.isSelected(),
        getExtraProperties());
    return attr;
  }
  private void updateDefaultMatchingRuleNames()
  {
    AttributeSyntax<?> syn = (AttributeSyntax<?>)syntax.getSelectedItem();
    if (syn != null)
    {
      MatchingRule[] rules = {syn.getApproximateMatchingRule(),
          syn.getSubstringMatchingRule(),
          syn.getEqualityMatchingRule(),
          syn.getOrderingMatchingRule()};
      JComboBox[] combos = {approximate, substring, equality, ordering};
      for (int i=0; i<rules.length; i++)
      {
        DefaultComboBoxModel model = (DefaultComboBoxModel)combos[i].getModel();
        int index = combos[i].getSelectedIndex();
        if (rules[i] != null)
        {
          if (model.getSize() > 0)
          {
            model.removeElementAt(0);
          }
          model.insertElementAt(INFO_CTRL_PANEL_DEFAULT_DEFINED_IN_SYNTAX.get(
              rules[i].getNameOrOID()), 0);
        }
        else
        {
          if (model.getSize() > 0)
          {
            model.removeElementAt(0);
          }
          model.insertElementAt(NO_MATCHING_RULE, 0);
        }
        combos[i].setSelectedIndex(index);
      }
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/CustomObjectClassPanel.java
@@ -29,41 +29,140 @@
import static org.opends.messages.AdminToolMessages.*;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.datamodel.SortableListModel;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.event.
 ConfigurationElementCreatedListener;
import org.opends.guitools.controlpanel.event.ScrollPaneBorderListener;
import org.opends.guitools.controlpanel.task.DeleteSchemaElementsTask;
import org.opends.guitools.controlpanel.task.ModifyObjectClassTask;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.components.BasicExpander;
import org.opends.guitools.controlpanel.ui.components.DoubleAddRemovePanel;
import org.opends.guitools.controlpanel.ui.components.TitlePanel;
import org.opends.guitools.controlpanel.ui.renderer.
 SchemaElementComboBoxCellRenderer;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.ObjectClassType;
import org.opends.server.types.Schema;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
/**
 * The panel that displays a custom object class definition.
 *
 */
public class CustomObjectClassPanel extends StandardObjectClassPanel
public class CustomObjectClassPanel extends SchemaElementPanel
{
  private static final long serialVersionUID = 2105520588901380L;
  private JButton delete;
  private JButton saveChanges;
  private ObjectClass objectClass;
  private String ocName;
  private ScrollPaneBorderListener scrollListener;
  private TitlePanel titlePanel = new TitlePanel(Message.EMPTY, Message.EMPTY);
  private JLabel lName = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_NAME_LABEL.get());
  private JLabel lParent = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get());
  private JLabel lOID = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_OID_LABEL.get());
  private JLabel lAliases = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_ALIASES_LABEL.get());
  private JLabel lOrigin = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_ORIGIN_LABEL.get());
  private JLabel lFile = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_FILE_LABEL.get());
  private JTextField aliases = Utilities.createLongTextField();
  private JLabel lDescription = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_DESCRIPTION_LABEL.get());
  private JLabel lType = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_TYPE_LABEL.get());
  private JLabel lAttributes = Utilities.createPrimaryLabel(
      INFO_CTRL_PANEL_OBJECTCLASS_ATTRIBUTES_LABEL.get());
  private Set<AttributeType> inheritedOptionalAttributes =
    new HashSet<AttributeType>();
  private Set<AttributeType> inheritedRequiredAttributes =
    new HashSet<AttributeType>();
  private JLabel[] labels = {lName, lParent, lOID, lAliases, lOrigin, lFile,
      lDescription, lType, lAttributes
  };
  private JTextField name = Utilities.createMediumTextField();
  private JComboBox parent = Utilities.createComboBox();
  private JComboBox type = Utilities.createComboBox();
  private JTextField oid = Utilities.createMediumTextField();
  private JTextField description = Utilities.createLongTextField();
  private JTextField origin = Utilities.createLongTextField();
  private JTextField file = Utilities.createLongTextField();
  private JCheckBox obsolete = Utilities.createCheckBox(
      INFO_CTRL_PANEL_OBJECTCLASS_OBSOLETE_LABEL.get());
  private DoubleAddRemovePanel<AttributeType> attributes;
  private Schema schema;
  private Set<String> lastAliases = new LinkedHashSet<String>();
  private boolean ignoreChangeEvents;
  /**
   * Default constructor of the panel.
   *
   */
  public CustomObjectClassPanel()
  {
    super();
    createLayout();
  }
  /**
   * {@inheritDoc}
   */
@@ -81,10 +180,11 @@
    GridBagConstraints gbc = new GridBagConstraints();
    p.setOpaque(false);
    p.setBorder(PANEL_BORDER);
    super.createBasicLayout(p, gbc);
    createBasicLayout(p, gbc);
    gbc = new GridBagConstraints();
    gbc.weightx = 1.0;
    gbc.weighty = 1.0;
    gbc.gridwidth = 2;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.gridx = 0;
    gbc.gridy = 0;
@@ -98,6 +198,7 @@
    gbc.anchor = GridBagConstraints.WEST;
    gbc.fill = GridBagConstraints.NONE;
    gbc.insets = new Insets(10, 10, 10, 10);
    gbc.gridwidth = 1;
    delete = Utilities.createButton(
        INFO_CTRL_PANEL_DELETE_OBJECTCLASS_BUTTON.get());
    delete.setOpaque(false);
@@ -112,6 +213,343 @@
        deleteObjectclass();
      }
    });
    gbc.anchor = GridBagConstraints.EAST;
    gbc.gridx ++;
    saveChanges =
      Utilities.createButton(INFO_CTRL_PANEL_SAVE_CHANGES_LABEL.get());
    saveChanges.setOpaque(false);
    add(saveChanges, gbc);
    saveChanges.addActionListener(new ActionListener()
    {
      /**
       * {@inheritDoc}
       */
      public void actionPerformed(ActionEvent ev)
      {
        ArrayList<Message> errors = new ArrayList<Message>();
        saveChanges(false, errors);
      }
    });
  }
  /**
   * Creates the basic layout of the panel.
   * @param c the container where all the components will be layed out.
   * @param gbc the grid bag constraints.
   */
  protected void createBasicLayout(Container c, GridBagConstraints gbc)
  {
    SchemaElementComboBoxCellRenderer renderer = new
    SchemaElementComboBoxCellRenderer(parent);
    DefaultComboBoxModel model = new DefaultComboBoxModel();
    parent.setModel(model);
    parent.setRenderer(renderer);
    ItemListener itemListener = new ItemListener()
    {
      /**
       * {@inheritDoc}
       */
      public void itemStateChanged(ItemEvent ev)
      {
        if (ignoreChangeEvents) return;
        updateAttributesWithParent(true);
      }
    };
    parent.addItemListener(itemListener);
    model = new DefaultComboBoxModel();
    for (ObjectClassType t : ObjectClassType.values())
    {
      model.addElement(t);
    }
    type.setModel(model);
    type.setSelectedItem(ObjectClassType.STRUCTURAL);
    type.setRenderer(renderer);
    attributes =
      new DoubleAddRemovePanel<AttributeType>(0, AttributeType.class);
    Comparator<AttributeType> comparator = new Comparator<AttributeType>()
    {
      /**
       * {@inheritDoc}
       */
      public int compare(AttributeType attr1, AttributeType attr2)
      {
        return attr1.getNameOrOID().compareTo(attr2.getNameOrOID());
      }
    };
    attributes.getAvailableListModel().setComparator(comparator);
    attributes.getSelectedListModel1().setComparator(comparator);
    attributes.getSelectedListModel2().setComparator(comparator);
    gbc.gridy = 0;
    gbc.gridwidth = 2;
    addErrorPane(c, gbc);
    gbc.gridy ++;
    gbc.anchor = GridBagConstraints.WEST;
    titlePanel.setTitle(INFO_CTRL_PANEL_OBJECTCLASS_DETAILS.get());
    gbc.fill = GridBagConstraints.NONE;
    gbc.insets.top = 5;
    gbc.insets.bottom = 7;
    c.add(titlePanel, gbc);
    gbc.insets.bottom = 0;
    gbc.insets.top = 8;
    gbc.gridy ++;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    Component[] basicComps = {name, oid, description, parent};
    JLabel[] basicLabels = {lName, lOID, lDescription, lParent};
    JLabel[] basicInlineHelp = new JLabel[] {null, null, null, null};
    add(basicLabels, basicComps, basicInlineHelp, c, gbc);
    gbc.gridx = 0;
    gbc.weightx = 0.0;
    gbc.insets.left = 0;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.anchor = GridBagConstraints.NORTHWEST;
    c.add(lAttributes, gbc);
    gbc.gridx ++;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.weightx = 1.0;
    gbc.weighty = 1.0;
    gbc.insets.left = 10;
    c.add(attributes, gbc);
    attributes.getAvailableLabel().setText(
        INFO_CTRL_PANEL_ADDREMOVE_AVAILABLE_ATTRIBUTES.get().toString());
    attributes.getSelectedLabel1().setText(
        INFO_CTRL_PANEL_ADDREMOVE_REQUIRED_ATTRIBUTES.get().toString());
    attributes.getSelectedLabel2().setText(
        INFO_CTRL_PANEL_ADDREMOVE_OPTIONAL_ATTRIBUTES.get().toString());
    AttributeTypeCellRenderer listRenderer = new AttributeTypeCellRenderer();
    attributes.getAvailableList().setCellRenderer(listRenderer);
    attributes.getSelectedList1().setCellRenderer(listRenderer);
    attributes.getSelectedList2().setCellRenderer(listRenderer);
    gbc.gridy ++;
    gbc.weighty = 0.0;
    gbc.insets.top = 3;
    JLabel explanation = Utilities.createInlineHelpLabel(
        INFO_CTRL_PANEL_INHERITED_ATTRIBUTES_HELP.get());
    gbc.insets.top = 3;
    c.add(explanation, gbc);
    final BasicExpander expander = new BasicExpander(
        INFO_CTRL_PANEL_EXTRA_OPTIONS_EXPANDER.get());
    obsolete.setText("Obsolete");
    Component[] comps = {aliases, origin, file, type, obsolete};
    JLabel[] labels = {lAliases, lOrigin, lFile, lType, null};
    JLabel[] inlineHelps = {
        Utilities.createInlineHelpLabel(
            INFO_CTRL_PANEL_SEPARATED_WITH_COMMAS_HELP.get()), null,
        Utilities.createInlineHelpLabel(
            INFO_CTRL_PANEL_SCHEMA_FILE_OBJECTCLASS_HELP.get(File.separator)),
            null, null};
    gbc.gridwidth = 2;
    gbc.gridx = 0;
    gbc.weighty = 0.0;
    gbc.insets.left = 0;
    gbc.gridy ++;
    c.add(expander, gbc);
    final JPanel p = new JPanel(new GridBagLayout());
    gbc.insets.left = 15;
    gbc.gridy ++;
    c.add(p, gbc);
    gbc.gridy ++;
    p.setOpaque(false);
    GridBagConstraints gbc1 = new GridBagConstraints();
    gbc1.fill = GridBagConstraints.HORIZONTAL;
    gbc1.gridy = 0;
    add(labels, comps, inlineHelps, p, gbc1);
    ChangeListener changeListener = new ChangeListener()
    {
      /**
       * {@inheritDoc}
       */
      public void stateChanged(ChangeEvent e)
      {
        p.setVisible(expander.isSelected());
      }
    };
    expander.addChangeListener(changeListener);
    expander.setSelected(false);
    changeListener.stateChanged(null);
    DocumentListener docListener = new DocumentListener()
    {
      /**
       * {@inheritDoc}
       */
      public void insertUpdate(DocumentEvent ev)
      {
        checkEnableSaveChanges();
      }
      /**
       * {@inheritDoc}
       */
      public void removeUpdate(DocumentEvent ev)
      {
        checkEnableSaveChanges();
      }
      /**
       * {@inheritDoc}
       */
      public void changedUpdate(DocumentEvent arg0)
      {
        checkEnableSaveChanges();
      }
    };
    JTextField[] tfs = {name, description, oid, aliases, origin, file};
    for (JTextField tf : tfs)
    {
      tf.getDocument().addDocumentListener(docListener);
    }
    ActionListener actionListener = new ActionListener()
    {
      public void actionPerformed(ActionEvent ev)
      {
        checkEnableSaveChanges();
      }
    };
    JComboBox[] combos = {parent, type};
    for (JComboBox combo : combos)
    {
      combo.addActionListener(actionListener);
    }
    ListDataListener dataListener = new ListDataListener()
    {
      /**
       * {@inheritDoc}
       */
      public void contentsChanged(ListDataEvent e)
      {
        checkEnableSaveChanges();
      }
      /**
       * {@inheritDoc}
       */
      public void intervalAdded(ListDataEvent e)
      {
        checkEnableSaveChanges();
      }
      /**
       * {@inheritDoc}
       */
      public void intervalRemoved(ListDataEvent e)
      {
        checkEnableSaveChanges();
      }
    };
    SortableListModel<AttributeType> list1 = attributes.getSelectedListModel1();
    SortableListModel<AttributeType> list2 = attributes.getSelectedListModel2();
    list1.addListDataListener(dataListener);
    list2.addListDataListener(dataListener);
    obsolete.addActionListener(actionListener);
  }
  /**
   * Updates the contents of the panel with the provided object class.
   * @param oc the object class.
   * @param schema the schema.
   */
  public void update(ObjectClass oc, Schema schema)
  {
    ignoreChangeEvents = true;
    objectClass = oc;
    if ((oc == null) || (schema == null))
    {
      // Ignore: this is called to get an initial panel size.
      return;
    }
    String n = oc.getPrimaryName();
    if (n == null)
    {
      n = NOT_APPLICABLE.toString();
    }
    titlePanel.setDetails(Message.raw(n));
    name.setText(n);
    SortableListModel<AttributeType> modelRequired =
      attributes.getSelectedListModel1();
    SortableListModel<AttributeType> modelAvailable =
      attributes.getSelectedListModel2();
    SortableListModel<AttributeType> availableModel =
      attributes.getAvailableListModel();
    availableModel.addAll(modelRequired.getData());
    availableModel.addAll(modelAvailable.getData());
    modelRequired.clear();
    modelAvailable.clear();
    parent.setSelectedItem(oc.getSuperiorClass());
    updateAttributesWithParent(false);
    for (AttributeType attr : oc.getRequiredAttributes())
    {
      availableModel.remove(attr);
      modelRequired.add(attr);
    }
    for (AttributeType attr : oc.getOptionalAttributes())
    {
      availableModel.remove(attr);
      modelAvailable.add(attr);
    }
    notifyAttributesChanged();
    oid.setText(oc.getOID());
    n = oc.getDescription();
    if (n == null)
    {
      n = "";
    }
    description.setText(n);
    Set<String> aliases = getAliases(oc);
    lastAliases.clear();
    lastAliases.addAll(aliases);
    this.aliases.setText(Utilities.getStringFromCollection(aliases, ", "));
    String sOrigin = Utilities.getOrigin(oc);
    if (sOrigin == null)
    {
      sOrigin = "";
    }
    origin.setText(sOrigin);
    String sFile = oc.getSchemaFile();
    if (sFile == null)
    {
      sFile = "";
    }
    file.setText(sFile);
    type.setSelectedItem(oc.getObjectClassType());
    obsolete.setSelected(oc.isObsolete());
    ocName = objectClass.getNameOrOID();
    scrollListener.updateBorder();
    for (JLabel label : labels)
    {
      setPrimaryValid(label);
    }
    saveChanges.setEnabled(false);
    ignoreChangeEvents = false;
  }
  /**
@@ -120,10 +558,67 @@
  public void configurationChanged(ConfigurationChangeEvent ev)
  {
    final ServerDescriptor desc = ev.getNewDescriptor();
    Schema s = desc.getSchema();
    final boolean schemaChanged;
    if (schema != null && s != null)
    {
      schemaChanged = !ServerDescriptor.areSchemasEqual(s, schema);
    }
    else if (schema == null && s != null)
    {
      schemaChanged = true;
    }
    else if (s == null && schema != null)
    {
      schemaChanged = false;
    }
    else
    {
      schemaChanged = false;
    }
    if (schemaChanged)
    {
      schema = s;
      HashMap<String, ObjectClass> objectClassNameMap = new HashMap<String,
      ObjectClass>();
      for (String key : schema.getObjectClasses().keySet())
      {
        ObjectClass oc = schema.getObjectClass(key);
        objectClassNameMap.put(oc.getNameOrOID(), oc);
      }
      SortedSet<String> orderedKeys = new TreeSet<String>();
      orderedKeys.addAll(objectClassNameMap.keySet());
      ArrayList<ObjectClass> newParents = new ArrayList<ObjectClass>();
      for (String key : orderedKeys)
      {
        newParents.add(objectClassNameMap.get(key));
      }
      updateComboBoxModel(newParents,
          ((DefaultComboBoxModel)parent.getModel()), new Comparator<Object>()
      {
        /**
         * {@inheritDoc}
         */
        public int compare(Object arg0, Object arg1)
        {
          return String.valueOf(arg0).compareTo(String.valueOf(arg1));
        }
      });
    updateErrorPaneIfAuthRequired(desc,
       isLocal() ?
          INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_OBJECTCLASS_DELETE.get() :
        INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_OBJECTCLASS_EDIT.get() :
      INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname()));
    }
    else if (schema == null)
    {
      updateErrorPane(errorPane,
          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_SUMMARY.get(),
          ColorAndFontConstants.errorTitleFont,
          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get(),
          ColorAndFontConstants.defaultFont);
    }
    SwingUtilities.invokeLater(new Runnable()
    {
      /**
@@ -131,7 +626,18 @@
       */
      public void run()
      {
        delete.setEnabled(!authenticationRequired(desc));
        delete.setEnabled(!authenticationRequired(desc)
            && !authenticationRequired(desc)
            && schema != null);
        checkEnableSaveChanges();
        saveChanges.setEnabled(saveChanges.isEnabled() &&
            !authenticationRequired(desc)
            && !authenticationRequired(desc)
            && schema != null);
        if (schemaChanged)
        {
          updateAttributes();
        }
      }
    });
  }
@@ -139,15 +645,52 @@
  /**
   * {@inheritDoc}
   */
  public void update(ObjectClass oc, Schema schema)
  public boolean mustCheckUnsavedChanges()
  {
    super.update(oc, schema);
    objectClass = oc;
    if (objectClass != null)
    {
      ocName = objectClass.getNameOrOID();
    return saveChanges.isEnabled();
    }
    scrollListener.updateBorder();
  /**
   * {@inheritDoc}
   */
  public UnsavedChangesDialog.Result checkUnsavedChanges()
  {
    UnsavedChangesDialog.Result result;
    UnsavedChangesDialog unsavedChangesDlg = new UnsavedChangesDialog(
          Utilities.getParentDialog(this), getInfo());
    unsavedChangesDlg.setMessage(INFO_CTRL_PANEL_UNSAVED_CHANGES_SUMMARY.get(),
        INFO_CTRL_PANEL_UNSAVED_OBJECTCLASS_CHANGES_DETAILS.get(
           objectClass.getNameOrOID()));
    Utilities.centerGoldenMean(unsavedChangesDlg,
          Utilities.getParentDialog(this));
    unsavedChangesDlg.setVisible(true);
    result = unsavedChangesDlg.getResult();
    if (result == UnsavedChangesDialog.Result.SAVE)
    {
      ArrayList<Message> errors = new ArrayList<Message>();
      saveChanges(true, errors);
      if (!errors.isEmpty())
      {
        result = UnsavedChangesDialog.Result.CANCEL;
      }
    }
    return result;
  }
  /**
   * {@inheritDoc}
   */
  public Component getPreferredFocusComponent()
  {
    return name;
  }
  /**
   * {@inheritDoc}
   */
  public void okClicked()
  {
  }
  private void deleteObjectclass()
@@ -157,9 +700,10 @@
        Utilities.createFrame(),
        Utilities.getParentDialog(this),
        INFO_CTRL_PANEL_DELETE_OBJECTCLASS_TITLE.get(), getInfo());
    ArrayList<ObjectClass> ocsToDelete = new ArrayList<ObjectClass>();
    LinkedHashSet<ObjectClass> ocsToDelete = new LinkedHashSet<ObjectClass>();
    ocsToDelete.add(objectClass);
    ArrayList<AttributeType> attrsToDelete = new ArrayList<AttributeType>();
    LinkedHashSet<AttributeType> attrsToDelete =
      new LinkedHashSet<AttributeType>(0);
    DeleteSchemaElementsTask newTask = new DeleteSchemaElementsTask(getInfo(),
        dlg, ocsToDelete, attrsToDelete);
@@ -168,9 +712,9 @@
      task.canLaunch(newTask, errors);
    }
    Schema schema = getInfo().getServerDescriptor().getSchema();
    ArrayList<String> childClasses = new ArrayList<String>();
    if (schema != null)
    {
      ArrayList<String> childClasses = new ArrayList<String>();
      for (ObjectClass o : schema.getObjectClasses().values())
      {
        if (objectClass.equals(o.getSuperiorClass()))
@@ -178,17 +722,26 @@
          childClasses.add(o.getNameOrOID());
        }
      }
      if (!childClasses.isEmpty())
      {
        errors.add(ERR_CANNOT_DELETE_PARENT_OBJECTCLASS.get(ocName,
            Utilities.getStringFromCollection(childClasses, ", "), ocName));
      }
    else
    {
      errors.add(ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get());
    }
    if (errors.size() == 0)
    {
      MessageBuilder mb = new MessageBuilder();
      if (!childClasses.isEmpty())
      {
        mb.append(INFO_OBJECTCLASS_IS_SUPERIOR.get(
            ocName,
            Utilities.getStringFromCollection(childClasses, ", ")));
        mb.append("<br>");
      }
      Message confirmationMessage =
        INFO_CTRL_PANEL_CONFIRMATION_DELETE_OBJECTCLASS_DETAILS.get(
            ocName);
      mb.append(confirmationMessage);
      if (displayConfirmationDialog(
          INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
          confirmationMessage))
@@ -209,4 +762,476 @@
      displayErrorDialog(errors);
    }
  }
  private void saveChanges(boolean modal, ArrayList<Message> errors)
  {
    for (JLabel label : labels)
    {
      setPrimaryValid(label);
    }
    String n = getObjectClassName();
    MessageBuilder err = new MessageBuilder();
    if (n.length() == 0)
    {
      errors.add(ERR_CTRL_PANEL_OBJECTCLASS_NAME_REQUIRED.get());
      setPrimaryInvalid(lName);
    }
    else if (!n.equalsIgnoreCase(objectClass.getNameOrOID()))
    {
      if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
      {
        errors.add(ERR_CTRL_PANEL_INVALID_OBJECTCLASS_NAME.get(err.toString()));
        setPrimaryInvalid(lName);
        err = new MessageBuilder();
      }
      else
      {
        Message elementType = NewAttributePanel.getSchemaElementType(n, schema);
        if (elementType != null)
        {
          errors.add(ERR_CTRL_PANEL_OBJECTCLASS_NAME_ALREADY_IN_USE.get(n,
              elementType.toString()));
          setPrimaryInvalid(lName);
        }
      }
    }
    n = oid.getText().trim();
    if (n.length() > 0 && !n.equalsIgnoreCase(objectClass.getOID()))
    {
      if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
      {
        errors.add(ERR_CTRL_PANEL_OID_NOT_VALID.get(err.toString()));
        setPrimaryInvalid(lOID);
        err = new MessageBuilder();
      }
      else
      {
        Message elementType = NewAttributePanel.getSchemaElementType(n, schema);
        if (elementType != null)
        {
          errors.add(ERR_CTRL_PANEL_OID_ALREADY_IN_USE.get(n,
              elementType.toString()));
          setPrimaryInvalid(lOID);
        }
      }
    }
    Collection<String> aliases = getAliases();
    Collection<String> oldAliases = getAliases(objectClass);
    if (!aliases.equals(oldAliases))
    {
      for (String alias : aliases)
      {
        if (alias.trim().length() == 0)
        {
          errors.add(ERR_CTRL_PANEL_EMPTY_ALIAS.get());
          setPrimaryInvalid(lAliases);
        }
        else
        {
          boolean notPreviouslyDefined = true;
          for (String oldAlias : oldAliases)
          {
            if (oldAlias.equalsIgnoreCase(alias))
            {
              notPreviouslyDefined = false;
              break;
            }
          }
          if (notPreviouslyDefined)
          {
            Message elementType =
              NewAttributePanel.getSchemaElementType(alias, schema);
            if (elementType != null)
            {
              errors.add(ERR_CTRL_PANEL_ALIAS_ALREADY_IN_USE.get(n,
                  elementType.toString()));
              setPrimaryInvalid(lAliases);
            }
          }
        }
      }
    }
    ObjectClass superior = getSuperior();
    if (superior != null)
    {
      if (superior.getNameOrOID().equalsIgnoreCase(objectClass.getNameOrOID()))
      {
        errors.add(ERR_CTRL_PANEL_OBJECTCLASS_CANNOT_BE_ITS_SUPERIOR.get());
        setPrimaryInvalid(lParent);
      }
      else
      {
        // Check whether this object class is defined as parent as the superior.
        superior = superior.getSuperiorClass();
        while (superior != null)
        {
          if (superior.getNameOrOID().equalsIgnoreCase(
              objectClass.getNameOrOID()))
          {
            errors.add(
                ERR_CTRL_PANEL_OBJECTCLASS_IS_SUPERIOR_OF_SUPERIOR.get(
                getSuperior().getNameOrOID()));
            setPrimaryInvalid(lParent);
            break;
          }
          superior = superior.getSuperiorClass();
        }
      }
    }
    if (errors.size() == 0)
    {
      ProgressDialog dlg = new ProgressDialog(
          Utilities.createFrame(),
          Utilities.getParentDialog(this),
          INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TITLE.get(), getInfo());
      ModifyObjectClassTask newTask = new ModifyObjectClassTask(getInfo(),
          dlg, objectClass, getNewObjectClass());
      for (ConfigurationElementCreatedListener listener :
        getConfigurationElementCreatedListeners())
      {
        newTask.addConfigurationElementCreatedListener(listener);
      }
      for (Task task : getInfo().getTasks())
      {
        task.canLaunch(newTask, errors);
      }
      if (errors.size() == 0)
      {
        launchOperation(newTask,
            INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_SUMMARY.get(ocName),
            INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_COMPLETE.get(),
            INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_SUCCESSFUL.get(ocName),
            ERR_CTRL_PANEL_MODIFYING_OBJECTCLASS_ERROR_SUMMARY.get(),
            ERR_CTRL_PANEL_MODIFYING_OBJECTCLASS_ERROR_DETAILS.get(ocName),
            null,
            dlg);
        dlg.setVisible(true);
      }
    }
    if (!errors.isEmpty())
    {
      displayErrorDialog(errors);
    }
  }
  private void checkEnableSaveChanges()
  {
    if (ignoreChangeEvents) return;
    boolean changed;
    if (objectClass != null)
    {
      try
      {
        changed = !objectClass.toString().equals(
            getNewObjectClass().toString());
      }
      catch (Throwable t)
      {
        changed = true;
      }
    }
    else
    {
      changed = false;
    }
    saveChanges.setEnabled(changed);
  }
  private Set<String> getAliases()
  {
    Set<String> al = new LinkedHashSet<String>();
    String s = aliases.getText().trim();
    if (s.length() > 0)
    {
      String[] a = s.split(",");
      for (String alias : a)
      {
        al.add(alias.trim());
      }
    }
    return al;
  }
  private String getObjectClassName()
  {
    return name.getText().trim();
  }
  private String getOID()
  {
    String o = oid.getText().trim();
    if (o.length() == 0)
    {
      o = getObjectClassName()+"-oid";
    }
    return o;
  }
  private Map<String, List<String>> getExtraProperties()
  {
    Map<String, List<String>> map = new HashMap<String, List<String>>();
    String f = file.getText().trim();
    if (f.length() > 0)
    {
      ArrayList<String> list = new ArrayList<String>();
      list.add(f);
      map.put(ServerConstants.SCHEMA_PROPERTY_FILENAME, list);
    }
    String or = origin.getText().trim();
    if (or.length() > 0)
    {
      ArrayList<String> list = new ArrayList<String>();
      list.add(or);
      map.put(ServerConstants.SCHEMA_PROPERTY_ORIGIN, list);
    }
    return map;
  }
  private ArrayList<String> getAllNames()
  {
    ArrayList<String> al = new ArrayList<String>();
    al.add(getObjectClassName());
    al.addAll(getAliases());
    return al;
  }
  private String getDescription()
  {
    return description.getText().trim();
  }
  private ObjectClass getSuperior()
  {
    return (ObjectClass)parent.getSelectedItem();
  }
  private ObjectClassType getObjectClassType()
  {
    return (ObjectClassType)type.getSelectedItem();
  }
  private Set<AttributeType> getRequiredAttributes()
  {
    HashSet<AttributeType> attrs = new HashSet<AttributeType>();
    attrs.addAll(attributes.getSelectedListModel1().getData());
    attrs.removeAll(inheritedRequiredAttributes);
    return attrs;
  }
  private Set<AttributeType> getOptionalAttributes()
  {
    HashSet<AttributeType> attrs = new HashSet<AttributeType>();
    attrs.addAll(attributes.getSelectedListModel2().getData());
    attrs.removeAll(inheritedOptionalAttributes);
    return attrs;
  }
  private ObjectClass getNewObjectClass()
  {
    ObjectClass newObjectClass = new ObjectClass("",
        getObjectClassName(),
        getAllNames(),
        getOID(),
        getDescription(),
        getSuperior(),
        getRequiredAttributes(),
        getOptionalAttributes(),
        getObjectClassType(),
        obsolete.isSelected(),
        getExtraProperties());
    return newObjectClass;
  }
  private void updateAttributes()
  {
    int[][] selected =
    {
      attributes.getAvailableList().getSelectedIndices(),
      attributes.getSelectedList1().getSelectedIndices(),
      attributes.getSelectedList2().getSelectedIndices()
    };
    JList[] lists =
    {
        attributes.getAvailableList(),
        attributes.getSelectedList1(),
        attributes.getSelectedList2()
    };
    attributes.getAvailableListModel().clear();
    Collection<AttributeType> allAttrs =
      schema.getAttributeTypes().values();
    attributes.getAvailableListModel().addAll(allAttrs);
    HashSet<AttributeType> toDelete = new HashSet<AttributeType>();
    for (AttributeType attr : attributes.getSelectedListModel1().getData())
    {
      if (!allAttrs.contains(attr))
      {
        toDelete.add(attr);
      }
      else
      {
        attributes.getAvailableListModel().remove(attr);
      }
    }
    for (AttributeType attr : toDelete)
    {
      attributes.getSelectedListModel1().remove(attr);
    }
    toDelete = new HashSet<AttributeType>();
    for (AttributeType attr : attributes.getSelectedListModel2().getData())
    {
      if (!allAttrs.contains(attr))
      {
        toDelete.add(attr);
      }
      else
      {
        attributes.getAvailableListModel().remove(attr);
      }
    }
    for (AttributeType attr : toDelete)
    {
      attributes.getSelectedListModel1().remove(attr);
    }
    int i = 0;
    for (int[] sel : selected)
    {
      if (sel != null)
      {
        ArrayList<Integer> indexes = new ArrayList<Integer>();
        for (int j=0; j<sel.length; j++)
        {
          if (sel[j] < lists[i].getModel().getSize())
          {
            indexes.add(sel[j]);
          }
        }
        int[] newSelection = new int[indexes.size()];
        for (int j=0; j<newSelection.length; j++)
        {
          newSelection[j] = indexes.get(j);
        }
        lists[i].setSelectedIndices(newSelection);
      }
      i++;
    }
  }
  private void updateAttributesWithParent(boolean notify)
  {
 // Remove the previous inherited attributes.
    for (AttributeType attr : inheritedRequiredAttributes)
    {
      attributes.getAvailableListModel().add(attr);
      attributes.getSelectedListModel1().remove(attr);
    }
    for (AttributeType attr : inheritedOptionalAttributes)
    {
      attributes.getAvailableListModel().add(attr);
      attributes.getSelectedListModel2().remove(attr);
    }
    inheritedOptionalAttributes.clear();
    inheritedRequiredAttributes.clear();
    ObjectClass p = (ObjectClass)parent.getSelectedItem();
    if (p != null)
    {
      for (AttributeType attr : p.getRequiredAttributeChain())
      {
        inheritedRequiredAttributes.add(attr);
      }
      for (AttributeType attr : p.getOptionalAttributeChain())
      {
        inheritedOptionalAttributes.add(attr);
      }
    }
    for (AttributeType attr : inheritedRequiredAttributes)
    {
      attributes.getAvailableListModel().remove(attr);
      attributes.getSelectedListModel1().add(attr);
    }
    for (AttributeType attr : inheritedOptionalAttributes)
    {
      attributes.getAvailableListModel().remove(attr);
      attributes.getSelectedListModel2().add(attr);
    }
    Collection<AttributeType> unmovableItems =
      new ArrayList<AttributeType>(inheritedRequiredAttributes);
    unmovableItems.addAll(inheritedOptionalAttributes);
    attributes.setUnmovableItems(unmovableItems);
    if (notify)
    {
      notifyAttributesChanged();
    }
  }
  private void notifyAttributesChanged()
  {
    attributes.getAvailableListModel().fireContentsChanged(
        attributes.getAvailableList(), 0,
        attributes.getAvailableListModel().getSize() - 1);
    attributes.getSelectedListModel1().fireContentsChanged(
        attributes.getSelectedList1(), 0,
        attributes.getSelectedListModel1().getSize() - 1);
    attributes.getSelectedListModel2().fireContentsChanged(
        attributes.getSelectedList2(), 0,
        attributes.getSelectedListModel2().getSize() - 1);
  }
  /**
   * A renderer for the attribute lists.  The renderer basically marks the
   * inherited attributes with an asterisk.
   *
   */
  private class AttributeTypeCellRenderer implements ListCellRenderer
  {
    private ListCellRenderer defaultRenderer;
    /**
     * Renderer constructor.
     *
     */
    public AttributeTypeCellRenderer()
    {
      defaultRenderer = attributes.getAvailableList().getCellRenderer();
    }
    /**
     * {@inheritDoc}
     */
    public Component getListCellRendererComponent(JList list, Object value,
        int index, boolean isSelected, boolean cellHasFocus)
    {
      if (value instanceof AttributeType)
      {
        AttributeType attr = (AttributeType)value;
        if (inheritedOptionalAttributes.contains(value) ||
            inheritedRequiredAttributes.contains(value))
        {
          value = attr.getNameOrOID()+ " (*)";
        }
        else
        {
          value = attr.getNameOrOID();
        }
      }
      return defaultRenderer.getListCellRendererComponent(list, value, index,
          isSelected, cellHasFocus);
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/NewAttributePanel.java
@@ -37,15 +37,12 @@
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
@@ -56,12 +53,11 @@
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.task.OfflineUpdateException;
import org.opends.guitools.controlpanel.task.OnlineUpdateException;
import org.opends.guitools.controlpanel.task.SchemaTask;
import org.opends.guitools.controlpanel.event.
 ConfigurationElementCreatedListener;
import org.opends.guitools.controlpanel.task.NewSchemaElementsTask;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.components.BasicExpander;
import
@@ -78,18 +74,8 @@
import org.opends.server.config.ConfigConstants;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeUsage;
import org.opends.server.types.Attributes;
import org.opends.server.types.CommonSchemaElements;
import org.opends.server.types.Entry;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.OpenDsException;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.Schema;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
@@ -207,7 +193,24 @@
    final boolean[] repack = {firstSchema};
    final boolean[] error = {false};
    if (s != null)
    boolean schemaChanged;
    if (schema != null && s != null)
    {
      schemaChanged = !ServerDescriptor.areSchemasEqual(s, schema);
    }
    else if (schema == null && s != null)
    {
      schemaChanged = true;
    }
    else if (s == null && schema != null)
    {
      schemaChanged = false;
    }
    else
    {
      schemaChanged = false;
    }
    if (schemaChanged)
    {
      schema = s;
@@ -310,7 +313,7 @@
        updateComboBoxModel(el, model);
      }
    }
    else
    else if (schema == null)
    {
      updateErrorPane(errorPane,
          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_SUMMARY.get(),
@@ -383,10 +386,12 @@
    if (n.length() == 0)
    {
      errors.add(ERR_CTRL_PANEL_ATTRIBUTE_NAME_REQUIRED.get());
      setPrimaryInvalid(lName);
    }
    else if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
    {
      errors.add(ERR_CTRL_PANEL_INVALID_ATTRIBUTE_NAME.get(err.toString()));
      setPrimaryInvalid(lName);
      err = new MessageBuilder();
    }
    else
@@ -396,6 +401,7 @@
      {
        errors.add(ERR_CTRL_PANEL_ATTRIBUTE_NAME_ALREADY_IN_USE.get(n,
            elementType.toString()));
        setPrimaryInvalid(lName);
      }
    }
@@ -405,6 +411,7 @@
      if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
      {
        errors.add(ERR_CTRL_PANEL_OID_NOT_VALID.get(err.toString()));
        setPrimaryInvalid(lOID);
        err = new MessageBuilder();
      }
      else
@@ -414,6 +421,7 @@
        {
          errors.add(ERR_CTRL_PANEL_OID_ALREADY_IN_USE.get(n,
              elementType.toString()));
          setPrimaryInvalid(lOID);
        }
      }
    }
@@ -428,6 +436,7 @@
          if (alias.trim().length() == 0)
          {
            errors.add(ERR_CTRL_PANEL_EMPTY_ALIAS.get());
            setPrimaryInvalid(lAliases);
          }
          else
          {
@@ -436,24 +445,44 @@
            {
              errors.add(ERR_CTRL_PANEL_ALIAS_ALREADY_IN_USE.get(n,
                  elementType.toString()));
              setPrimaryInvalid(lAliases);
            }
          }
        }
      }
    }
    setPrimaryValid(lUsage);
    if (nonModifiable.isSelected())
    {
      if (AttributeUsage.USER_APPLICATIONS.equals(usage.getSelectedItem()))
      {
        errors.add(ERR_NON_MODIFIABLE_CANNOT_BE_USER_APPLICATIONS.get());
        setPrimaryInvalid(lUsage);
      }
    }
    ProgressDialog dlg = new ProgressDialog(
        Utilities.createFrame(),
        Utilities.getParentDialog(this),
        INFO_CTRL_PANEL_NEW_ATTRIBUTE_PANEL_TITLE.get(), getInfo());
    NewAttributeTask newTask = null;
    NewSchemaElementsTask newTask = null;
    if (errors.size() == 0)
    {
      newTask = new NewAttributeTask(getInfo(), dlg);
      LinkedHashSet<AttributeType> attributes =
        new LinkedHashSet<AttributeType>();
      attributes.add(getAttribute());
      LinkedHashSet<ObjectClass> ocs = new LinkedHashSet<ObjectClass>(0);
      newTask = new NewSchemaElementsTask(getInfo(), dlg, ocs, attributes);
      for (Task task : getInfo().getTasks())
      {
        task.canLaunch(newTask, errors);
      }
      for (ConfigurationElementCreatedListener listener :
        getConfigurationElementCreatedListeners())
      {
        newTask.addConfigurationElementCreatedListener(listener);
      }
    }
    if (errors.size() == 0)
    {
@@ -834,11 +863,17 @@
    return map;
  }
  private String getDescription()
  {
    return description.getText().trim();
  }
  private AttributeType getAttribute()
  {
    AttributeType attr = new AttributeType("", getAttributeName(),
        getAllNames(),
        getOID(), description.getText().trim(),
        getOID(),
        getDescription(),
        getSuperior(),
        (AttributeSyntax<?>)syntax.getSelectedItem(),
        getApproximateMatchingRule(),
@@ -852,228 +887,4 @@
    return attr;
  }
  /**
   * The task in charge of creating the attribute.
   *
   */
  protected class NewAttributeTask extends SchemaTask
  {
    private AttributeType attribute;
    private String attributeName;
    private String attributeDefinition;
    private String attributeWithoutFileDefinition;
    /**
     * The constructor of the task.
     * @param info the control panel info.
     * @param dlg the progress dialog that shows the progress of the task.
     */
    public NewAttributeTask(ControlPanelInfo info, ProgressDialog dlg)
    {
      super(info, dlg);
      attributeName = getAttributeName();
      attributeDefinition = attribute.toString();
      AttributeType attr = getAttribute();
      attr.setExtraProperty(ServerConstants.SCHEMA_PROPERTY_FILENAME,
          (String)null);
      attributeWithoutFileDefinition = attr.toString();
    }
    /**
     * {@inheritDoc}
     */
    public Type getType()
    {
      return Type.NEW_ATTRIBUTE;
    }
    /**
     * {@inheritDoc}
     */
    protected CommonSchemaElements getSchemaElement()
    {
      if (attribute == null)
      {
        attribute = getAttribute();
      }
      return attribute;
    }
    /**
     * {@inheritDoc}
     */
    public Message getTaskDescription()
    {
      return INFO_CTRL_PANEL_NEW_ATTRIBUTE_TASK_DESCRIPTION.get(attributeName);
    }
    /**
     * {@inheritDoc}
     */
    protected String getSchemaFileAttributeName()
    {
      return "attributeTypes";
    }
    /**
     * {@inheritDoc}
     */
    protected String getSchemaFileAttributeValue()
    {
      if (isServerRunning())
      {
        return attributeDefinition;
      }
      else
      {
        return attributeWithoutFileDefinition;
      }
    }
    /**
     * {@inheritDoc}
     */
    protected void updateSchema() throws OpenDsException
    {
      SwingUtilities.invokeLater(new Runnable()
      {
        /**
         * {@inheritDoc}
         */
        public void run()
        {
          printEquivalentCommandToAdd();
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_CREATING_ATTRIBUTE_PROGRESS.get(
                      attributeName),
                  ColorAndFontConstants.progressFont));
        }
      });
      if (isServerRunning())
      {
        try
        {
          BasicAttribute attr =
            new BasicAttribute(getSchemaFileAttributeName());
          attr.add(getSchemaFileAttributeValue());
          ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE,
              attr);
          getInfo().getDirContext().modifyAttributes(
              ConfigConstants.DN_DEFAULT_SCHEMA_ROOT,
              new ModificationItem[]  { mod });
        }
        catch (NamingException ne)
        {
          throw new OnlineUpdateException(
              ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne.toString()), ne);
        }
      }
      else
      {
        updateSchemaFile();
      }
      notifyConfigurationElementCreated(attribute);
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressDone(ColorAndFontConstants.progressFont));
        }
      });
    }
    /**
     * Updates the contents of the schema file.
     * @throws OpenDsException if an error occurs updating the schema file.
     */
    private void updateSchemaFile() throws OpenDsException
    {
      if (isSchemaFileDefined)
      {
        LDIFExportConfig exportConfig =
          new LDIFExportConfig(schemaFile,
                               ExistingFileBehavior.OVERWRITE);
        LDIFReader reader = null;
        Entry schemaEntry = null;
        try
        {
          reader = new LDIFReader(new LDIFImportConfig(schemaFile));
          schemaEntry = reader.readEntry();
          Modification mod = new Modification(ModificationType.ADD,
              Attributes.create(getSchemaFileAttributeName().toLowerCase(),
                  getSchemaFileAttributeValue()));
          schemaEntry.applyModification(mod);
          LDIFWriter writer = new LDIFWriter(exportConfig);
          writer.writeEntry(schemaEntry);
          exportConfig.getWriter().newLine();
        }
        catch (Throwable t)
        {
        }
        finally
        {
          if (reader != null)
          {
            try
            {
              reader.close();
            }
            catch (Throwable t)
            {
            }
          }
          if (exportConfig != null)
          {
            try
            {
              exportConfig.close();
            }
            catch (Throwable t)
            {
            }
          }
        }
      }
      else
      {
        LDIFExportConfig exportConfig =
          new LDIFExportConfig(schemaFile,
                               ExistingFileBehavior.FAIL);
        try
        {
          ArrayList<String> lines = getSchemaEntryLines();
          for (String line : lines)
          {
            LDIFWriter.writeLDIFLine(new StringBuilder(line),
                exportConfig.getWriter(), exportConfig.getWrapColumn() > 1,
                exportConfig.getWrapColumn());
          }
          exportConfig.getWriter().newLine();
        }
        catch (Throwable t)
        {
          throw new OfflineUpdateException(
              ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(t.toString()), t);
        }
        finally
        {
          if (exportConfig != null)
          {
            try
            {
              exportConfig.close();
            }
            catch (Throwable t)
            {
            }
          }
        }
      }
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/NewObjectClassPanel.java
@@ -40,16 +40,13 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
@@ -62,12 +59,11 @@
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.task.OfflineUpdateException;
import org.opends.guitools.controlpanel.task.OnlineUpdateException;
import org.opends.guitools.controlpanel.task.SchemaTask;
import org.opends.guitools.controlpanel.event.
 ConfigurationElementCreatedListener;
import org.opends.guitools.controlpanel.task.NewSchemaElementsTask;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.components.BasicExpander;
import org.opends.guitools.controlpanel.ui.components.DoubleAddRemovePanel;
@@ -78,20 +74,9 @@
import org.opends.messages.MessageBuilder;
import org.opends.server.config.ConfigConstants;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.opends.server.types.CommonSchemaElements;
import org.opends.server.types.Entry;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.ObjectClassType;
import org.opends.server.types.OpenDsException;
import org.opends.server.types.Schema;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
@@ -187,7 +172,24 @@
    final boolean[] repack = {firstSchema};
    final boolean[] error = {false};
    if (s != null)
    final boolean schemaChanged;
    if (schema != null && s != null)
    {
      schemaChanged = !ServerDescriptor.areSchemasEqual(s, schema);
    }
    else if (schema == null && s != null)
    {
      schemaChanged = true;
    }
    else if (s == null && schema != null)
    {
      schemaChanged = false;
    }
    else
    {
      schemaChanged = false;
    }
    if (schemaChanged)
    {
      schema = s;
@@ -230,8 +232,11 @@
          {
            parent.setSelectedItem(schema.getObjectClass("top"));
          }
          if (schemaChanged)
          {
          updateAttributes();
        }
        }
        if (repack[0])
        {
          packParentDialog();
@@ -332,14 +337,23 @@
        Utilities.createFrame(),
        Utilities.getParentDialog(this),
        INFO_CTRL_PANEL_NEW_OBJECTCLASS_PANEL_TITLE.get(), getInfo());
    NewObjectClassTask newTask = null;
    NewSchemaElementsTask newTask = null;
    if (errors.size() == 0)
    {
      newTask = new NewObjectClassTask(getInfo(), dlg);
      LinkedHashSet<AttributeType> attributes =
        new LinkedHashSet<AttributeType>(1);
      LinkedHashSet<ObjectClass> ocs = new LinkedHashSet<ObjectClass>();
      ocs.add(getObjectClass());
      newTask = new NewSchemaElementsTask(getInfo(), dlg, ocs, attributes);
      for (Task task : getInfo().getTasks())
      {
        task.canLaunch(newTask, errors);
      }
      for (ConfigurationElementCreatedListener listener :
        getConfigurationElementCreatedListeners())
      {
        newTask.addConfigurationElementCreatedListener(listener);
      }
    }
    if (errors.size() == 0)
    {
@@ -712,13 +726,19 @@
    return al;
  }
  private String getDescription()
  {
    return description.getText().trim();
  }
  private ObjectClass getObjectClass()
  {
    ObjectClass oc = new ObjectClass("", getObjectClassName(), getAllNames(),
        getOID(), description.getText().trim(),
        getOID(),
        getDescription(),
        getSuperior(),
        getRequiredAttributes(),
        getAllowedAttributes(),
        getOptionalAttributes(),
        getObjectClassType(),
        obsolete.isSelected(),
        getExtraProperties());
@@ -735,243 +755,19 @@
  {
    HashSet<AttributeType> attrs = new HashSet<AttributeType>();
    attrs.addAll(attributes.getSelectedListModel1().getData());
    attrs.removeAll(inheritedRequiredAttributes);
    return attrs;
  }
  private Set<AttributeType> getAllowedAttributes()
  private Set<AttributeType> getOptionalAttributes()
  {
    HashSet<AttributeType> attrs = new HashSet<AttributeType>();
    attrs.addAll(attributes.getSelectedListModel2().getData());
    attrs.removeAll(inheritedOptionalAttributes);
    return attrs;
  }
  /**
   * The task in charge of creating the object class.
   *
   */
  protected class NewObjectClassTask extends SchemaTask
  {
    private ObjectClass oc;
    private String ocName;
    private String ocDefinition;
    private String ocWithoutFileDefinition;
    /**
     * The constructor of the task.
     * @param info the control panel info.
     * @param dlg the progress dialog that shows the progress of the task.
     */
    public NewObjectClassTask(ControlPanelInfo info, ProgressDialog dlg)
    {
      super(info, dlg);
      ocName = getObjectClassName();
      ocDefinition = getSchemaElement().toString();
      ObjectClass oc = getObjectClass();
      oc.setExtraProperty(ServerConstants.SCHEMA_PROPERTY_FILENAME,
          (String)null);
      ocWithoutFileDefinition = oc.toString();
    }
    /**
     * {@inheritDoc}
     */
    public Type getType()
    {
      return Type.NEW_OBJECTCLASS;
    }
    /**
     * {@inheritDoc}
     */
    protected CommonSchemaElements getSchemaElement()
    {
      if (oc == null)
      {
        oc = getObjectClass();
      }
      return oc;
    }
    /**
     * {@inheritDoc}
     */
    public Message getTaskDescription()
    {
      return INFO_CTRL_PANEL_NEW_OBJECTCLASS_TASK_DESCRIPTION.get(ocName);
    }
    /**
     * {@inheritDoc}
     */
    protected String getSchemaFileAttributeName()
    {
      return "objectClasses";
    }
    /**
     * {@inheritDoc}
     */
    protected String getSchemaFileAttributeValue()
    {
      if (isServerRunning())
      {
        return ocDefinition;
      }
      else
      {
        return ocWithoutFileDefinition;
      }
    }
    /**
     * {@inheritDoc}
     */
    protected void updateSchema() throws OpenDsException
    {
      SwingUtilities.invokeLater(new Runnable()
      {
        /**
         * {@inheritDoc}
         */
        public void run()
        {
          printEquivalentCommandToAdd();
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressWithPoints(
                  INFO_CTRL_PANEL_CREATING_OBJECTCLASS_PROGRESS.get(ocName),
                  ColorAndFontConstants.progressFont));
        }
      });
      if (isServerRunning())
      {
        try
        {
          BasicAttribute attr =
            new BasicAttribute(getSchemaFileAttributeName());
          attr.add(getSchemaFileAttributeValue());
          ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE,
              attr);
          getInfo().getDirContext().modifyAttributes(
              ConfigConstants.DN_DEFAULT_SCHEMA_ROOT,
              new ModificationItem[]  { mod });
        }
        catch (NamingException ne)
        {
          throw new OnlineUpdateException(
              ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne.toString()), ne);
        }
      }
      else
      {
        updateSchemaFile();
      }
      notifyConfigurationElementCreated(oc);
      SwingUtilities.invokeLater(new Runnable()
      {
        /**
         * {@inheritDoc}
         */
        public void run()
        {
          getProgressDialog().appendProgressHtml(
              Utilities.getProgressDone(ColorAndFontConstants.progressFont));
        }
      });
    }
    /**
     * Updates the contents of the schema file.
     * @throws OpenDsException if an error occurs updating the schema file.
     */
    private void updateSchemaFile() throws OpenDsException
    {
      if (isSchemaFileDefined)
      {
        LDIFExportConfig exportConfig =
          new LDIFExportConfig(schemaFile,
                               ExistingFileBehavior.OVERWRITE);
        LDIFReader reader = null;
        Entry schemaEntry = null;
        try
        {
          reader = new LDIFReader(new LDIFImportConfig(schemaFile));
          schemaEntry = reader.readEntry();
          Modification mod = new Modification(ModificationType.ADD,
              Attributes.create(getSchemaFileAttributeName().toLowerCase(),
                  getSchemaFileAttributeValue()));
          schemaEntry.applyModification(mod);
          LDIFWriter writer = new LDIFWriter(exportConfig);
          writer.writeEntry(schemaEntry);
          exportConfig.getWriter().newLine();
        }
        catch (Throwable t)
        {
        }
        finally
        {
          if (reader != null)
          {
            try
            {
              reader.close();
            }
            catch (Throwable t)
            {
            }
          }
          if (exportConfig != null)
          {
            try
            {
              exportConfig.close();
            }
            catch (Throwable t)
            {
            }
          }
        }
      }
      else
      {
        LDIFExportConfig exportConfig =
          new LDIFExportConfig(schemaFile,
                               ExistingFileBehavior.FAIL);
        try
        {
          ArrayList<String> lines = getSchemaEntryLines();
          for (String line : lines)
          {
            LDIFWriter.writeLDIFLine(new StringBuilder(line),
                exportConfig.getWriter(), exportConfig.getWrapColumn() > 1,
                exportConfig.getWrapColumn());
          }
          exportConfig.getWriter().newLine();
        }
        catch (Throwable t)
        {
          throw new OfflineUpdateException(
              ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(t.toString()), t);
        }
        finally
        {
          if (exportConfig != null)
          {
            try
            {
              exportConfig.close();
            }
            catch (Throwable t)
            {
            }
          }
        }
      }
    }
  }
  /**
   * A renderer for the attribute lists.  The renderer basically marks the
   * inherited attributes with an asterisk.
   *
opends/src/guitools/org/opends/guitools/controlpanel/ui/SchemaBrowserRightPanel.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui;
@@ -37,6 +37,8 @@
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.event.
 ConfigurationElementCreatedListener;
import org.opends.guitools.controlpanel.event.SchemaElementSelectionListener;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
@@ -74,8 +76,9 @@
  private final SchemaElementPanel[] panels =
  {   standardObjectClassPanel, configurationObjectClassPanel,
      customObjectClassPanel, standardAttributePanel,
      configurationAttributePanel, customAttributePanel, matchingRulePanel,
      customObjectClassPanel,
      standardAttributePanel, configurationAttributePanel, customAttributePanel,
      matchingRulePanel,
      attributeSyntaxPanel
  };
@@ -145,6 +148,34 @@
  }
  /**
   * Adds a configuration element created listener.
   * @param listener the listener.
   */
  public void addConfigurationElementCreatedListener(
      ConfigurationElementCreatedListener listener)
  {
    super.addConfigurationElementCreatedListener(listener);
    for (SchemaElementPanel panel : panels)
    {
      panel.addConfigurationElementCreatedListener(listener);
    }
  }
  /**
   * Removes a configuration element created listener.
   * @param listener the listener.
   */
  public void removeConfigurationElementCreatedListener(
      ConfigurationElementCreatedListener listener)
  {
    super.removeConfigurationElementCreatedListener(listener);
    for (SchemaElementPanel panel : panels)
    {
      panel.removeConfigurationElementCreatedListener(listener);
    }
  }
  /**
   * Updates the contents of the panel with the provided standard object class.
   * @param oc the object class.
   * @param schema the schema.
@@ -242,7 +273,7 @@
   * @param syntax the attribute syntax.
   * @param schema the schema.
   */
  public void updateAttributeSyntax(AttributeSyntax syntax, Schema schema)
  public void updateAttributeSyntax(AttributeSyntax<?> syntax, Schema schema)
  {
    attributeSyntaxPanel.update(syntax, schema);
    schemaElementPanel = attributeSyntaxPanel;
@@ -348,9 +379,9 @@
  /**
   * Tells whether the user chose to save the changes in the panel, to not save
   * them or simply cancelled the selection in the tree.
   * them or simply canceled the selection in the tree.
   * @return the value telling whether the user chose to save the changes in the
   * panel, to not save them or simply cancelled the selection in the tree.
   * panel, to not save them or simply canceled the selection in the tree.
   */
  public UnsavedChangesDialog.Result checkUnsavedChanges()
  {
opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java
@@ -47,6 +47,7 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -55,6 +56,8 @@
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.NamingEnumeration;
import javax.naming.directory.SearchControls;
@@ -143,6 +146,9 @@
  private static final String MAIN_PANEL = "mainPanel";
  private static final String MESSAGE_PANEL = "messagePanel";
  private static final Logger LOG =
    Logger.getLogger(StatusGenericPanel.class.getName());
  /**
   * The error pane.
   */
@@ -538,7 +544,7 @@
  public void addConfigurationElementCreatedListener(
      ConfigurationElementCreatedListener listener)
  {
    confListeners.add(listener);
    getConfigurationElementCreatedListeners().add(listener);
  }
  /**
@@ -548,7 +554,7 @@
  public void removeConfigurationElementCreatedListener(
      ConfigurationElementCreatedListener listener)
  {
    confListeners.remove(listener);
    getConfigurationElementCreatedListeners().remove(listener);
  }
  /**
@@ -558,7 +564,8 @@
   */
  protected void notifyConfigurationElementCreated(Object configObject)
  {
    for (ConfigurationElementCreatedListener listener : confListeners)
    for (ConfigurationElementCreatedListener listener :
      getConfigurationElementCreatedListeners())
    {
      listener.elementCreated(
          new ConfigurationElementCreatedEvent(this, configObject));
@@ -566,6 +573,16 @@
  }
  /**
   * Returns the list of configuration listeners.
   * @return the list of configuration listeners.
   */
  protected List<ConfigurationElementCreatedListener>
  getConfigurationElementCreatedListeners()
  {
    return confListeners;
  }
  /**
   * Notification that cancel was clicked, the panel is in charge
   * of doing whatever is required (close the dialog, etc.).
   *
@@ -1404,6 +1421,20 @@
  protected void updateComboBoxModel(final Collection<?> newElements,
      final DefaultComboBoxModel model)
  {
    updateComboBoxModel(newElements, model, null);
  }
  /**
   * Updates a combo box model with a number of items.
   * @param newElements the new items for the combo box model.
   * @param model the combo box model to be updated.
   * @param comparator the object that will be used to compare the objects in
   * the model.  If <CODE>null</CODE>, the equals method will be used.
   */
  protected void updateComboBoxModel(final Collection<?> newElements,
      final DefaultComboBoxModel model,
      final Comparator<Object> comparator)
  {
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
@@ -1414,7 +1445,15 @@
          int i = 0;
          for (Object newElement : newElements)
          {
            if (comparator == null)
            {
            changed = !newElement.equals(model.getElementAt(i));
            }
            else
            {
              changed =
                comparator.compare(newElement, model.getElementAt(i)) != 0;
            }
            if (changed)
            {
              break;
@@ -1799,6 +1838,7 @@
          if (t != null)
          {
            LOG.log(Level.WARNING, "Error occurred running task: "+t, t);
            if ((task.getReturnCode() != null) &&
                (errorDetailCode != null))
            {
opends/src/guitools/org/opends/guitools/controlpanel/util/ControlPanelLog.java
@@ -61,7 +61,7 @@
      for (String packageName : packages)
      {
        Logger logger = Logger.getLogger(packageName);
        logger.setUseParentHandlers(false); // disable logging to console
        //logger.setUseParentHandlers(false); // disable logging to console
        logger.addHandler(fileHandler);
      }
      Logger logger = Logger.getLogger(packages[0]);
@@ -78,7 +78,7 @@
   */
  static public void initPackage(String packageName) throws IOException {
    Logger logger = Logger.getLogger(packageName);
    logger.setUseParentHandlers(false); // disable logging to console
    //logger.setUseParentHandlers(false); // disable logging to console
    logger.addHandler(fileHandler);
    logger.log(Level.INFO, getInitialLogRecord());
  }
opends/src/messages/messages/admin_tool.properties
@@ -1104,6 +1104,8 @@
INFO_CTRL_PANEL_DELETING_INDEX=Deleting index '%s'
INFO_CTRL_PANEL_DELETING_VLV_INDEX=Deleting VLV index '%s'
INFO_CTRL_PANEL_CONFIRMATION_DELETE_SCHEMA_ELEMENTS_MSG=Are you sure you want \
 to delete the elements '%s' defined in the schema?
INFO_CTRL_PANEL_DELETE_SCHEMA_ELEMENT_TASK_DESCRIPTION=Delete schema elements.
INFO_CTRL_PANEL_DELETING_OBJECTCLASS=Deleting objectclass '%s'
INFO_CTRL_PANEL_DELETING_ATTRIBUTE=Deleting attribute '%s'
@@ -1113,11 +1115,16 @@
 configuration.  Details: %s
MILD_ERR_CTRL_PANEL_ERROR_CHECKING_ENTRY=Error checking entry.  Details: %s
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_SCHEMA_ELEMENT_OFFLINE=This operation \
 is equivalent to removing the following attribute from the schema definition \
 entry (cn=schema) in file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_SCHEMA_ELEMENT_ONLINE=Equivalent \
command line to update the schema:
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_ATTRIBUTE_OFFLINE=Deleting attribute \
 '%s' can also be done removing the following attribute from the schema \
 definition entry (cn=schema) in file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_OBJECTCLASS_OFFLINE=Deleting object \
 class '%s' can also be done removing the following attribute from the schema \
 definition entry (cn=schema) in file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_ATTRIBUTE_ONLINE=Equivalent \
command line to delete attribute '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_OBJECTCLASS_ONLINE=Equivalent \
command line to delete object class '%s':
INFO_CTRL_PANEL_MODIFY_ENTRY_TASK_DESCRIPTION=Modify entry '%s'.
INFO_CTRL_PANEL_RENAMING_ENTRY=Renaming entry '%s' to '%s'
INFO_CTRL_PANEL_MODIFYING_ENTRY=Modifying entry '%s'
@@ -1152,14 +1159,15 @@
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_START_SERVER=Equivalent command line to \
 start the server:
INFO_CTRL_PANEL_SERVER_STOPPED=Server Stopped
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ELEMENT_OFFLINE=This operation is \
 equivalent to adding the following attribute to the schema definition entry \
 (cn=schema) in file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ENTRY_OFFLINE=This operation is \
 equivalent to adding the following entry to the file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ELEMENT_ONLINE=Equivalent command \
 line to update the schema:
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ENTRY_OFFLINE=Adding the schema \
 elements '%s' can also be done adding the following entry to the file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ELEMENT_OFFLINE=Adding the schema \
 elements '%s' can also be done adding the following attributes to the \
 schema definition entry (cn=schema) in file '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_ATTRIBUTE_ONLINE=Equivalent \
command line to add attribute '%s':
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_OBJECTCLASS_ONLINE=Equivalent \
command line to add object class '%s':
MILD_ERR_CTRL_PANEL_BACKEND_NOT_FOUND_SUMMARY=Could not find backend
MILD_ERR_CTRL_PANEL_BACKEND_NOT_FOUND_DETAILS=The backend '%s' could not be \
 found.  Check main panel for more information.
@@ -1608,7 +1616,7 @@
INFO_CTRL_PANEL_SCHEMA_ELEMENT_NAME=Name
INFO_CTRL_PANEL_SCHEMA_ELEMENT_TYPE=Type
INFO_CTRL_PANEL_PARENT_CLASS=Parent Class
INFO_CTRL_PANEL_PARENT_CLASS=Superior Class
INFO_CTRL_PANEL_CHILD_CLASS=Child Class
INFO_CTRL_PANEL_REQUIRED_ATTRIBUTES=Required Attributes
INFO_CTRL_PANEL_OPTIONAL_ATTRIBUTES=Optional Attributes
@@ -1618,25 +1626,29 @@
INFO_CTRL_PANEL_CATEGORY_ITEM_SELECTED=Category Item Selected
INFO_CTRL_PANEL_MULTIPLE_SCHEMA_ITEMS_SELECTED=Multiple Schema Items Selected
MILD_ERR_CANNOT_DELETE_PARENT_OBJECTCLASS=ObjectClass '%s' is superior of the \
 following classes: %s.  You must redefine these classes so that they do not \
 inherit from objectClass '%s' before deleting it.
MILD_ERR_CANNOT_DELETE_PARENT_ATTRIBUTE=Attribute '%s' is superior of the \
 following attributes: %s.  You must redefine these attributes so that they do \
 not inherit from attribute '%s' before deleting it.
MILD_ERR_CANNOT_DELETE_ATTRIBUTE_WITH_DEPENDENCIES=Attribute '%s' is optional \
 or required by the following objectClasses: %s.  You must redefine these \
 classes so that they do not depend on attribute '%s' before deleting it.
MILD_ERR_CANNOT_MODIFY_PARENT_ATTRIBUTE=Attribute '%s' is superior of the \
 following attributes: %s.  You must redefine these attributes so that they do \
 not inherit from attribute '%s' before modifying it.
INFO_OBJECTCLASS_IS_SUPERIOR=Object class '%s' is superior of the \
 following object classes: %s.  If you continue, these object classes will be \
 updated with a new superior.
INFO_OBJECTCLASSES_ARE_SUPERIOR=The selected object classes are superior of \
 the following object classes: %s.  If you continue, these object classes will \
 be updated with a new superior.
INFO_ATTRIBUTE_IS_SUPERIOR=Attribute '%s' is superior of the \
 following attributes: %s.  If you continue, these attributes will be updated \
 with a new superior.
INFO_ATTRIBUTES_ARE_SUPERIOR=The selected attributes are superior of the \
 following attributes: %s.  If you continue, these attributes will be updated \
 with a new superior.
INFO_ATTRIBUTE_WITH_DEPENDENCIES=Attribute '%s' is optional or required by the \
 following object classes: %s.  If you continue, the definition of the object \
 classes will be modified.
INFO_ATTRIBUTES_WITH_DEPENDENCIES=The selected attributes are optional or \
 required by the following object classes: %s.  If you continue, the \
 definition of the object classes will be modified.
INFO_CTRL_PANEL_MANAGE_SCHEMA_TITLE=Manage Schema
INFO_CTRL_PANEL_DELETE_OBJECTCLASSES_TITLE=Delete Objectclasses
INFO_CTRL_PANEL_DELETE_ATTRIBUTES_TITLE=Delete Attributes
INFO_CTRL_PANEL_DELETE_OBJECTCLASSES_AND_ATTRIBUTES_TITLE=Delete Objectclasses \
 and Attributes
INFO_CTRL_PANEL_CONFIRMATION_DELETE_SCHEMA_ELEMENTS_DETAILS=Are you sure you \
 want to delete the elements '%s' defined in the schema?
INFO_CTRL_PANEL_DELETING_SCHEMA_ELEMENTS_SUMMARY=Deleting...
INFO_CTRL_PANEL_DELETING_SCHEMA_ELEMENTS_COMPLETE=Schema Definitions Deleted
INFO_CTRL_PANEL_DELETING_SCHEMA_ELEMENTS_SUCCESSFUL=The schema elements '%s' \
@@ -1653,6 +1665,7 @@
INFO_CTRL_PANEL_DELETE_ATTRIBUTE_BUTTON=Delete Attribute...
INFO_CTRL_PANEL_DELETE_ATTRIBUTE_TITLE=Delete Attribute
INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TITLE=Modify Attribute
INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_ATTRIBUTE_DELETE=The server is \
 running.  You must provide authentication to delete the attribute.
INFO_CTRL_PANEL_CONFIRMATION_DELETE_ATTRIBUTE_DETAILS=Are you sure you want to \
@@ -1663,13 +1676,30 @@
 successfully deleted
MILD_ERR_CTRL_PANEL_DELETING_ATTRIBUTE_ERROR_SUMMARY=Error deleting \
 attribute
MILD_ERR_CTRL_PANEL_DELETING_ATTRIBUTE_ERROR_DETAILS=An error occurred deleting \
 attribute '%s'.  Check details for more information.
MILD_ERR_CTRL_PANEL_DELETING_ATTRIBUTE_ERROR_DETAILS=An error occurred \
 deleting attribute '%s'.  Check details for more information.
INFO_CTRL_PANEL_MODIFYING_ATTRIBUTE_SUMMARY=Modifying attribute '%s'...
INFO_CTRL_PANEL_MODIFYING_ATTRIBUTE_COMPLETE=Attribute Modified
INFO_CTRL_PANEL_MODIFYING_ATTRIBUTE_SUCCESSFUL=The attribute '%s' was \
 successfully modified
MILD_ERR_CTRL_PANEL_MODIFYING_ATTRIBUTE_ERROR_SUMMARY=Error modifying \
 attribute
MILD_ERR_CTRL_PANEL_MODIFYING_ATTRIBUTE_ERROR_DETAILS=An error occurred \
 modifying attribute '%s'.  Check details for more information.
INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_SUMMARY=Modifying object class '%s'...
INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_COMPLETE=Object Class Modified
INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_SUCCESSFUL=The object class '%s' was \
 successfully modified
MILD_ERR_CTRL_PANEL_MODIFYING_OBJECTCLASS_ERROR_SUMMARY=Error modifying \
 object class
MILD_ERR_CTRL_PANEL_MODIFYING_OBJECTCLASS_ERROR_DETAILS=An error occurred \
 modifying object class '%s'.  Check details for more information.
INFO_CTRL_PANEL_DELETE_OBJECTCLASS_BUTTON=Delete Object Class...
INFO_CTRL_PANEL_DELETE_OBJECTCLASS_TITLE=Delete Object Class
INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_OBJECTCLASS_DELETE=The server is \
 running.  You must provide authentication to delete the object class.
INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_OBJECTCLASS_EDIT=The server is \
 running.  You must provide authentication to edit the object class.
INFO_CTRL_PANEL_CONFIRMATION_DELETE_OBJECTCLASS_DETAILS=Are you sure you want \
 to delete the object class '%s' defined in the schema?
INFO_CTRL_PANEL_DELETING_OBJECTCLASS_SUMMARY=Deleting object class '%s'...
@@ -2073,7 +2103,19 @@
MILD_ERR_CTRL_PANEL_EMPTY_ALIAS=You have provided an empty alias.
MILD_ERR_CTRL_PANEL_ALIAS_ALREADY_IN_USE=The provided alias '%s' \
 already exists in the schema (defined as %s).
MILD_ERR_NON_MODIFIABLE_CANNOT_BE_USER_APPLICATIONS=Non Modifiable attributes \
 must have an operational usage.
MILD_ERR_CTRL_PANEL_ATTRIBUTE_CANNOT_BE_ITS_SUPERIOR=An attribute cannot be \
 its own superior.
MILD_ERR_CTRL_PANEL_OBJECTCLASS_CANNOT_BE_ITS_SUPERIOR=An object class cannot \
 be its own superior.
MILD_ERR_CTRL_PANEL_OBJECTCLASS_IS_SUPERIOR_OF_SUPERIOR=The object class is \
 superior (directly or indirectly) of '%s'.
MILD_ERR_CTRL_PANEL_ATTRIBUTE_IS_SUPERIOR_OF_SUPERIOR=The attribute is \
 superior (directly or indirectly) of '%s'.
INFO_CTRL_PANEL_CREATING_ATTRIBUTE_SUMMARY=Creating attribute '%s'...
INFO_CTRL_PANEL_UPDATING_SCHEMA_FILE_PROGRESS=Adding schema elements to schema \
 file '%s'...
INFO_CTRL_PANEL_CREATING_ATTRIBUTE_COMPLETE=Attribute created in schema
INFO_CTRL_PANEL_CREATING_ATTRIBUTE_SUCCESSFUL=The attribute '%s' was \
 successfully created.
@@ -2104,9 +2146,28 @@
INFO_CTRL_PANEL_DEFAULT_DEFINED_IN_SYNTAX=- Default defined in syntax (%s) -
INFO_CTRL_PANEL_NEW_ATTRIBUTE_TASK_DESCRIPTION=Create new attribute '%s' in \
 schema.
INFO_CTRL_PANEL_NEW_ATTRIBUTES_TASK_DESCRIPTION=Creating new attributes '%s' \
 in schema.
INFO_CTRL_PANEL_NEW_OBJECTCLASSES_TASK_DESCRIPTION=Creating new object classes \
 '%s' in schema.
INFO_CTRL_PANEL_NEW_SCHEMA_ELEMENTS_TASK_DESCRIPTION=Creating attributes '%s' \
 and object classes '%s' in schema.
INFO_CTRL_PANEL_EXPLANATION_TO_MODIFY_ATTRIBUTE=To modify attribute '%s' it \
 will be deleted and then recreated.  The same applies to all the schema \
 elements that have references to it.
INFO_CTRL_PANEL_EXPLANATION_TO_MODIFY_OBJECTCLASS=To modify object class '%s' \
 it will be deleted and then recreated.  The same applies to all the schema \
 elements that have references to it.
INFO_CTRL_PANEL_EXPLANATION_TO_DELETE_REFERENCED_ELEMENTS=To modify \
 references to the deleted attributes and object classes the schema elements \
 that refer to them must be deleted and then added again.
INFO_CTRL_PANEL_CREATING_ATTRIBUTE_PROGRESS=Creating attribute '%s'
INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TASK_DESCRIPTION=Modify attribute '%s' in \
 schema
INFO_CTRL_PANEL_MODIFY_OBJECTCLASS_TASK_DESCRIPTION=Modify object class '%s' \
 in schema
INFO_CTRL_PANEL_ATTRIBUTE_NAME_LABEL=Name:
INFO_CTRL_PANEL_ATTRIBUTE_PARENT_LABEL=Parent:
INFO_CTRL_PANEL_ATTRIBUTE_PARENT_LABEL=Superior:
INFO_CTRL_PANEL_ATTRIBUTE_OID_LABEL=OID:
INFO_CTRL_PANEL_ATTRIBUTE_ALIASES_LABEL=Aliases:
INFO_CTRL_PANEL_ATTRIBUTE_ORIGIN_LABEL=Origin:
@@ -2274,7 +2335,7 @@
 in schema.
INFO_CTRL_PANEL_CREATING_OBJECTCLASS_PROGRESS=Creating object class '%s'
INFO_CTRL_PANEL_OBJECTCLASS_NAME_LABEL=Name:
INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL=Parent:
INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL=Superior:
INFO_CTRL_PANEL_OBJECTCLASS_OID_LABEL=OID:
INFO_CTRL_PANEL_OBJECTCLASS_ALIASES_LABEL=Aliases:
INFO_CTRL_PANEL_OBJECTCLASS_ORIGIN_LABEL=Origin: