From 6411dcff8da8710f140a8782967ddf0876f52b81 Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Mon, 31 May 2010 09:55:31 +0000
Subject: [PATCH] Provide the necessary operational attributes for External Changelog entries, to make them LDAP compliant and to allow browsing them through the Control-Panel. Improve browsing in the Control-Panel to make use of hasSubordinates as well as numSubordinates operational attributes. Improve Control-Panel look and feel when browsing the ECL

---
 opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java           |  117 +++++++++++
 opends/src/server/org/opends/server/monitors/BackendMonitor.java                              |    4 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java                  |   22 ++
 opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java       |   31 ++
 opends/src/guitools/org/opends/guitools/controlpanel/ui/LDAPEntryPanel.java                   |   12 -
 opends/src/server/org/opends/server/types/Entry.java                                          |    4 
 opends/src/guitools/org/opends/guitools/controlpanel/browser/NodeRefresher.java               |    8 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BrowserNodeInfo.java            |    8 
 opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java |  341 +++++++++++++++++++++------------
 opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java         |   13 +
 opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteEntryTask.java                |    2 
 11 files changed, 406 insertions(+), 156 deletions(-)

diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java b/opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java
index 92c68e4..e953acc 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java
@@ -33,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -59,6 +60,7 @@
 
 import org.opends.admin.ads.ADSContext;
 import org.opends.admin.ads.util.ConnectionUtils;
+import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
 import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
 import org.opends.guitools.controlpanel.event.BrowserEvent;
 import org.opends.guitools.controlpanel.event.BrowserEventListener;
@@ -1276,6 +1278,7 @@
 
     v.add("objectClass");
     v.add("numsubordinates");
+    v.add("hassubordinates");
     v.add("ref");
     if ((displayFlags & DISPLAY_ACI_COUNT) != 0) {
       v.add("aci");
@@ -1315,6 +1318,7 @@
       return new String[] {
           "objectClass",
           "numsubordinates",
+          "hassubordinates",
           "ref",
           "aci",
           displayAttribute};
@@ -1322,6 +1326,7 @@
       return new String[] {
           "objectClass",
           "numsubordinates",
+          "hassubordinates",
           "ref",
           "aci"
       };
@@ -1656,9 +1661,8 @@
       // numSubOrdinates attribute. If the child entry's DN
       // is found in the hacker's list, then we ignore
       // the numSubordinate attribute... :((
-      int numSubOrdinates = child.getNumSubOrdinates();
       boolean hasNoSubOrdinates;
-      if ((numSubOrdinates == 0) && dontTrust) {
+      if (!child.hasSubOrdinates() && dontTrust) {
         LDAPURL childUrl = findUrlForDisplayedEntry(child);
         if (numSubordinateHacker.contains(childUrl)) {
           // The numSubOrdinates we have is unreliable.
@@ -1673,7 +1677,7 @@
         }
       }
       else {
-        hasNoSubOrdinates = (numSubOrdinates == 0);
+        hasNoSubOrdinates = !child.hasSubOrdinates();
       }
 
 
@@ -1740,6 +1744,15 @@
     if (entry != null) {
       // Get the numsubordinates
       node.setNumSubOrdinates(getNumSubOrdinates(entry));
+      if (node.getNumSubOrdinates() > 0)
+      {
+        node.setHasSubOrdinates(true);
+      }
+      else
+      {
+        // Calculate based also in the hasSubordinates attribute
+        node.setHasSubOrdinates(getHasSubOrdinates(entry));
+      }
       node.setReferral(getReferral(entry));
       Set<String> ocValues = ConnectionUtils.getValues(entry, "objectClass");
       if (ocValues != null) {
@@ -1766,7 +1779,7 @@
 
     // Select the icon according the objectClass,...
     int modifiers = 0;
-    if (node.isLeaf() && (node.getNumSubOrdinates() <= 0)) {
+    if (node.isLeaf() && !node.hasSubOrdinates()) {
       modifiers |= IconPool.MODIFIER_LEAF;
     }
     if (node.getReferral() != null) {
@@ -2073,6 +2086,91 @@
     return result;
   }
 
+  /**
+   * Returns whether the entry has subordinates or not.  It uses an algorithm
+   * based in hassubordinates and numsubordinates attributes.
+   * @param entry the entry to analyze.
+   * @throws NamingException if an error occurs.
+   * @return {@code true} if the entry has subordinates according to the values
+   * of hasSubordinates and numSubordinates, returns {@code false} if none of
+   * the attributes could be found.
+   */
+  public static boolean getHasSubOrdinates(SearchResult entry)
+  throws NamingException
+  {
+    boolean result;
+
+    String v = ConnectionUtils.getFirstValue(entry, "hassubordinates");
+    if (v == null) {
+      result = getNumSubOrdinates(entry) > 0;
+    }
+    else {
+      result = "true".equalsIgnoreCase(v);
+    }
+
+    return result;
+  }
+
+  /**
+   * Get the value of the numsubordinates attribute.
+   * If numsubordinates is not present, returns 0.
+   * @param entry the entry to analyze.
+   * @return the value of the numsubordinate attribute.  0 if the attribute
+   * could not be found.
+   */
+  public static int getNumSubOrdinates(CustomSearchResult entry)
+  {
+    int result;
+
+    List<Object> vs = entry.getAttributeValues("numsubordinates");
+    String v = null;
+    if (vs != null && !vs.isEmpty())
+    {
+      v = vs.get(0).toString();
+    }
+    if (v == null) {
+      result = 0;
+    }
+    else {
+      try {
+        result = Integer.parseInt(v);
+      }
+      catch(NumberFormatException x) {
+        result = 0;
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Returns whether the entry has subordinates or not.  It uses an algorithm
+   * based in hassubordinates and numsubordinates attributes.
+   * @param entry the entry to analyze.
+   * @return {@code true} if the entry has subordinates according to the values
+   * of hasSubordinates and numSubordinates, returns {@code false} if none of
+   * the attributes could be found.
+   */
+  public static boolean getHasSubOrdinates(CustomSearchResult entry)
+  {
+    boolean result;
+
+    List<Object> vs = entry.getAttributeValues("hassubordinates");
+    String v = null;
+    if (vs != null && !vs.isEmpty())
+    {
+      v = vs.get(0).toString();
+    }
+    if (v == null) {
+      result = getNumSubOrdinates(entry) > 0;
+    }
+    else {
+      result = "true".equalsIgnoreCase(v);
+    }
+
+    return result;
+  }
+
 
   /**
    * Returns the value of the 'ref' attribute.
@@ -2210,6 +2308,7 @@
     boolean isRootNode;
     String[] referral;
     int numSubOrdinates;
+    boolean hasSubOrdinates;
     int errorType;
     Exception errorException;
     Object errorArg;
@@ -2229,6 +2328,7 @@
       isSuffix = node instanceof SuffixNode;
       referral = node.getReferral();
       numSubOrdinates = node.getNumSubOrdinates();
+      hasSubOrdinates = node.hasSubOrdinates();
       objectClassValues = node.getObjectClassValues();
       if (node.getError() != null) {
         BasicNodeError error = node.getError();
@@ -2319,6 +2419,15 @@
     }
 
     /**
+     * Returns whether the entry has subordinates or not.
+     * @return {@code true} if the entry has subordinates and {@code false}
+     * otherwise.
+     */
+    public boolean hasSubOrdinates() {
+      return hasSubOrdinates;
+    }
+
+    /**
      * Returns the error type associated we got when refreshing the node.
      * <CODE>null</CODE> if no error was found.
      * @return the error type associated we got when refreshing the node.
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/browser/NodeRefresher.java b/opends/src/guitools/org/opends/guitools/controlpanel/browser/NodeRefresher.java
index 698d22f..f7e3c7c 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/browser/NodeRefresher.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/browser/NodeRefresher.java
@@ -406,6 +406,7 @@
       {
         localEntry = s.next();
         localEntry.setName(node.getDN());
+
       }
       if (localEntry == null) {
         /* Not enough rights to read the entry or the entry simply does not
@@ -606,7 +607,7 @@
     }
     else {
       SearchResult entry = getDisplayedEntry();
-      isLeafNode = (BrowserController.getNumSubOrdinates(entry) == 0);
+      isLeafNode = !BrowserController.getHasSubOrdinates(entry);
     }
   }
 
@@ -670,8 +671,8 @@
   private boolean isNumSubOrdinatesUsable() throws NamingException {
     boolean result;
     SearchResult entry = getDisplayedEntry();
-    int numSubOrdinates = BrowserController.getNumSubOrdinates(entry);
-    if (numSubOrdinates == 0) { // We must check
+    boolean hasSubOrdinates = BrowserController.getHasSubOrdinates(entry);
+    if (!hasSubOrdinates) { // We must check
       LDAPURL url = getDisplayedUrl();
       if (controller.getNumSubordinateHacker().contains(url)) {
         // The numSubOrdinate we have is unreliable.
@@ -699,6 +700,7 @@
     InitialLdapContext ctx = null;
     BasicNode parentNode = getNode();
     parentNode.setSizeLimitReached(false);
+
     try {
       // Send an LDAP search
       SearchControls ctls = controller.getBasicSearchControls();
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteEntryTask.java b/opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteEntryTask.java
index 775d164..6d4ac1f 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteEntryTask.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/task/DeleteEntryTask.java
@@ -239,7 +239,7 @@
             InitialLdapContext ctx =
               controller.findConnectionForDisplayedEntry(node);
             useAdminCtx = controller.isConfigurationNode(node);
-            if (node.getNumSubOrdinates() > 0)
+            if (node.hasSubOrdinates())
             {
               deleteSubtreeWithControl(ctx, dn, path, toNotify);
             }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
index 094849d..ef6520e 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
@@ -756,11 +756,19 @@
         }
         else if (!added && !displayAll)
         {
-          BasicNode rootNode =
-            (BasicNode)controller.getTree().getModel().getRoot();
-          if (controller.findChildNode(rootNode, s) == -1)
+          if (isChangeLog(theDN))
           {
-            controller.addNodeUnderRoot(s);
+            // Consider it a suffix
+            controller.addSuffix(s, null);
+          }
+          else
+          {
+            BasicNode rootNode =
+              (BasicNode)controller.getTree().getModel().getRoot();
+            if (controller.findChildNode(rootNode, s) == -1)
+            {
+              controller.addNodeUnderRoot(s);
+            }
           }
         }
       }
@@ -776,6 +784,21 @@
     }
   }
 
+  private boolean isChangeLog(DN theDN)
+  {
+    try
+    {
+      return theDN.equals(
+          DN.decode(ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT));
+    }
+    catch (Throwable t)
+    {
+      // Bug
+      t.printStackTrace();
+    }
+    return false;
+  }
+
   /**
    * Returns the LDAP filter built based in the parameters provided by the user.
    * @return the LDAP filter built based in the parameters provided by the user.
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/LDAPEntryPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/LDAPEntryPanel.java
index 8979783..36f830f 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/LDAPEntryPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/LDAPEntryPanel.java
@@ -36,7 +36,6 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
-import java.util.List;
 
 import javax.swing.JButton;
 import javax.swing.JPanel;
@@ -627,15 +626,8 @@
   {
     final ArrayList<Message> errors = new ArrayList<Message>();
     // Check that the entry is correct.
-    // Rely in numsubordinates...
-    boolean isLeaf = true;
-
-    List<Object> o = searchResult.getAttributeValues("numsubordinates");
-    if (!o.isEmpty())
-    {
-      int numsubordinates = Integer.parseInt((String)o.iterator().next());
-      isLeaf = numsubordinates <= 0;
-    }
+    // Rely in numsubordinates and hassubordinates
+    boolean isLeaf = !BrowserController.getHasSubOrdinates(searchResult);
 
     if (treePath != null)
     {
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
index bf7480e..cf4413f 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
@@ -483,6 +483,17 @@
         else
         {
           gbc.anchor = GridBagConstraints.WEST;
+          if (values.size() == 1)
+          {
+            Object v = values.get(0);
+            if (v instanceof String)
+            {
+              if (((String)v).indexOf("\n") != -1)
+              {
+                gbc.anchor = GridBagConstraints.NORTHWEST;
+              }
+            }
+          }
         }
         gbc.insets.left = 0;
         gbc.gridwidth = GridBagConstraints.RELATIVE;
@@ -739,7 +750,7 @@
     Schema schema = getInfo().getServerDescriptor().getSchema();
     if (isRootEntry)
     {
-      String[] attrsNotToAdd = {"entryuuid", "hasnumsubordinates",
+      String[] attrsNotToAdd = {"entryuuid", "hassubordinates",
           "numsubordinates", "subschemasubentry", "entrydn",
       "hassubordinates"};
       for (String attr : sr.getAttributeNames())
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java
index 1fb1481..fe0c444 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java
@@ -57,6 +57,10 @@
   private String[] referral;
   private int numSubOrdinates;
 
+  // This is required for the case where there is an undefined number of
+  // subordinates (for instance in the case of the changelog).
+  private boolean hasSubOrdinates;
+
   private String displayName;
   private Icon icon;
   private int fontStyle;
@@ -76,6 +80,7 @@
     isLeaf = true;
     refreshNeededOnExpansion = true;
     numSubOrdinates = -1;
+    hasSubOrdinates = false;
     displayName = "";
   }
 
@@ -277,6 +282,23 @@
   }
 
   /**
+   * Returns whether the entry has subordinates or not.
+   * @return {@code true} if the entry has subordinates and {@code false}
+   * otherwise.
+   */
+  public boolean hasSubOrdinates() {
+    return hasSubOrdinates;
+  }
+
+  /**
+   * Sets the whether the entry has subordinates or not.
+   * @param hasSubOrdinates whether the entry has subordinates or not.
+   */
+  public void setHasSubOrdinates(boolean hasSubOrdinates) {
+    this.hasSubOrdinates = hasSubOrdinates;
+  }
+
+  /**
    * Returns the referrals of the entry. Returns <CODE>null</CODE> if this node
    * is not a referral.
    * @return the referrals of the entry. Returns <CODE>null</CODE> if this node
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BrowserNodeInfo.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BrowserNodeInfo.java
index 342ba30..b52f979 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BrowserNodeInfo.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BrowserNodeInfo.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2008-2010 Sun Microsystems, Inc.
  */
 
 package org.opends.guitools.controlpanel.ui.nodes;
@@ -84,6 +84,12 @@
 
 
   /**
+   * Returns the value of hassubordinates for the entry.
+   * @return the value of hassubordinates for the entry.
+   */
+  public boolean hasSubOrdinates();
+
+  /**
    * Returns the referrals attached to the displayed entry.
    * This is the value of the 'ref' attribute.
    * Returns <CODE>null</CODE> if the attribute is not present.
diff --git a/opends/src/server/org/opends/server/monitors/BackendMonitor.java b/opends/src/server/org/opends/server/monitors/BackendMonitor.java
index ecfaab1..eab5a82 100644
--- a/opends/src/server/org/opends/server/monitors/BackendMonitor.java
+++ b/opends/src/server/org/opends/server/monitors/BackendMonitor.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.monitors;
 
@@ -222,7 +222,7 @@
     else
     {
       // This is done to avoid recalculating the number of entries
-      // using the hasNumSubordinates method in the case where the
+      // using the numSubordinates method in the case where the
       // backend has a single base DN.
       String s = backendCount + " " + baseDNs[0].toString();
       builder.add(AttributeValues.create(baseDNEntryCountType, s));
diff --git a/opends/src/server/org/opends/server/types/Entry.java b/opends/src/server/org/opends/server/types/Entry.java
index e7dc0e8..5e86373 100644
--- a/opends/src/server/org/opends/server/types/Entry.java
+++ b/opends/src/server/org/opends/server/types/Entry.java
@@ -5427,8 +5427,8 @@
             AttributeType t = e.getKey();
             if (t.hasNameOrOID(lowerName))
             {
-              mergeAttributeLists(e.getValue(), userAttrsCopy, t,
-                  attrName, options, omitValues, omitReal,
+              mergeAttributeLists(e.getValue(), operationalAttrsCopy,
+                  t, attrName, options, omitValues, omitReal,
                   omitVirtual);
               continue;
             }
diff --git a/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java b/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
index 4ac2932..f351404 100644
--- a/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -40,6 +40,7 @@
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -112,6 +113,7 @@
 import org.opends.server.types.operation.SearchReferenceSearchOperation;
 import org.opends.server.util.Base64;
 import org.opends.server.util.ServerConstants;
+import org.opends.server.config.ConfigConstants;
 
 
 
@@ -605,39 +607,43 @@
     // Start a specific ECL session
     eclSession = replicationServer.createECLSession(startECLSessionMsg);
 
-    if (!getScope().equals(SearchScope.SINGLE_LEVEL))
-    {
-      // Root entry
-      Entry entry = createRootEntry();
-      if (matchFilter(entry))
-        returnEntry(entry, null);
-    }
-
     if (true)
     {
       // Loop on result entries
       int INITIAL=0;
       int PSEARCH=1;
       int phase=INITIAL;
+      boolean returnedRoot = false;
       while (true)
       {
-
         // Check for a request to cancel this operation.
         checkIfCanceled(false);
 
         ECLUpdateMsg update = eclSession.getNextUpdate();
         if (update!=null)
         {
+          if (!returnedRoot)
+          {
+            returnRootEntryIfRequired(true);
+            returnedRoot = true;
+          }
           if (phase==INITIAL)
+          {
             if (!buildAndReturnEntry(update))
             {
               // Abandon, Size limit reached
               eclSession.close();
               break;
             }
+          }
         }
         else
         {
+          if (!returnedRoot)
+          {
+            returnRootEntryIfRequired(false);
+            returnedRoot = true;
+          }
           if (phase==INITIAL)
           {
             if (this.persistentSearch == null)
@@ -656,6 +662,18 @@
     }
   }
 
+  private void returnRootEntryIfRequired(boolean hasSubordinates)
+  throws DirectoryException
+  {
+    if (!getScope().equals(SearchScope.SINGLE_LEVEL))
+    {
+      // Root entry
+      Entry entry = createRootEntry(hasSubordinates);
+      if (matchFilter(entry))
+        returnEntry(entry, null);
+    }
+  }
+
   private boolean supportsControl(String oid)
   {
     return ((supportedControls != null) &&
@@ -849,22 +867,68 @@
 
   /**
    * Creates the root entry of the external changelog.
+   * @param hasSubordinates whether the root entry has subordinates or not.
    * @return The root entry created.
    */
-  private Entry createRootEntry()
+  private Entry createRootEntry(boolean hasSubordinates)
   {
     HashMap<ObjectClass,String> oclasses =
       new LinkedHashMap<ObjectClass,String>(3);
-    oclasses.putAll(eclObjectClasses);
 
+    // Objectclass
+    HashMap<ObjectClass,String> rootObjectClasses =
+      new LinkedHashMap<ObjectClass,String>(2);
+    ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
+    rootObjectClasses.put(topOC, OC_TOP);
+    ObjectClass containerOC = DirectoryServer.getObjectClass("container", true);
+    rootObjectClasses.put(containerOC, "container");
+    oclasses.putAll(rootObjectClasses);
     HashMap<AttributeType,List<Attribute>> userAttrs =
       new LinkedHashMap<AttributeType,List<Attribute>>();
-
     HashMap<AttributeType,List<Attribute>> operationalAttrs =
       new LinkedHashMap<AttributeType,List<Attribute>>();
 
-    Entry e = new Entry(this.rootBaseDN, oclasses, userAttrs,
-        operationalAttrs);
+    // subSchemaSubentry
+    AttributeType aType =
+      DirectoryServer.getAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC);
+    if (aType == null)
+      aType = DirectoryServer.getDefaultAttributeType(ATTR_SUBSCHEMA_SUBENTRY);
+    Attribute a = Attributes.create(ATTR_SUBSCHEMA_SUBENTRY,
+        ConfigConstants.DN_DEFAULT_SCHEMA_ROOT);
+    List<Attribute> attrList = Collections.singletonList(a);
+    if (aType.isOperational())
+      operationalAttrs.put(aType, attrList);
+    else
+      userAttrs.put(aType, attrList);
+
+    // TODO:numSubordinates
+
+    // hasSubordinates
+    if (hasSubordinates)
+    {
+      aType = DirectoryServer.getAttributeType("hassubordinates");
+      if (aType == null)
+        aType = DirectoryServer.getDefaultAttributeType("hasSubordinates");
+      a = Attributes.create("hasSubordinates", "true");
+      attrList = Collections.singletonList(a);
+      if (aType.isOperational())
+        operationalAttrs.put(aType, attrList);
+      else
+        userAttrs.put(aType, attrList);
+    }
+
+    // entryDN
+    aType = DirectoryServer.getAttributeType("entrydn");
+    if (aType == null)
+      aType = DirectoryServer.getDefaultAttributeType("entryDN");
+    a = Attributes.create("entryDN", rootBaseDN.toNormalizedString());
+    attrList = Collections.singletonList(a);
+    if (aType.isOperational())
+      operationalAttrs.put(aType, attrList);
+    else
+      userAttrs.put(aType, attrList);
+
+    Entry e = new Entry(this.rootBaseDN, oclasses, userAttrs, operationalAttrs);
     return e;
   }
 
@@ -901,7 +965,7 @@
       String delInitiatorsName)
   throws DirectoryException
   {
-    AttributeType attributeType;
+    AttributeType aType;
 
     String dnString = "";
     String pattern;
@@ -909,7 +973,7 @@
     {
       // Draft uncompat mode
       dnString = "replicationcsn="+ changeNumber +"," + serviceID
-        + "," + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
+      + "," + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
     }
     else
     {
@@ -917,6 +981,8 @@
       dnString = "changenumber="+ draftChangenumber + "," +
       ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
     }
+
+    // Objectclass
     HashMap<ObjectClass,String> oClasses =
       new LinkedHashMap<ObjectClass,String>(3);
     oClasses.putAll(eclObjectClasses);
@@ -931,40 +997,80 @@
     HashMap<AttributeType,List<Attribute>> operationalAttrs =
       new LinkedHashMap<AttributeType,List<Attribute>>();
 
-    ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
+    // Operational standard attributes
+
+    // subSchemaSubentry
+    aType = DirectoryServer.getAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC);
+    if (aType == null)
+    aType = DirectoryServer.getDefaultAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC);
+    Attribute a = Attributes.create(ATTR_SUBSCHEMA_SUBENTRY_LC,
+        ConfigConstants.DN_DEFAULT_SCHEMA_ROOT);
+    List<Attribute> attrList = Collections.singletonList(a);
+    if (aType.isOperational())
+      operationalAttrs.put(aType, attrList);
+    else
+      uAttrs.put(aType, attrList);
+
+    // numSubordinates
+    aType = DirectoryServer.getAttributeType("numsubordinates");
+    if (aType == null)
+      aType = DirectoryServer.getDefaultAttributeType("numSubordinates");
+    a = Attributes.create("numSubordinates", "0");
+    attrList = Collections.singletonList(a);
+    if (aType.isOperational())
+      operationalAttrs.put(aType, attrList);
+    else
+      uAttrs.put(aType, attrList);
+
+    // hasSubordinates
+    aType = DirectoryServer.getAttributeType("hassubordinates");
+    if (aType == null)
+      aType = DirectoryServer.getDefaultAttributeType("hasSubordinates");
+    a = Attributes.create("hasSubordinates", "false");
+    attrList = Collections.singletonList(a);
+    if (aType.isOperational())
+      operationalAttrs.put(aType, attrList);
+    else
+      uAttrs.put(aType, attrList);
+
+    // entryDN
+    aType = DirectoryServer.getAttributeType("entrydn");
+    if (aType == null)
+      aType = DirectoryServer.getDefaultAttributeType("entryDN");
+    a = Attributes.create("entryDN", dnString);
+    attrList = Collections.singletonList(a);
+    if (aType.isOperational())
+      operationalAttrs.put(aType, attrList);
+    else
+      uAttrs.put(aType, attrList);
 
     // REQUIRED attributes
 
     // ECL Changelog draft change number
-    if((attributeType =
-      DirectoryServer.getAttributeType("changenumber")) == null)
-      attributeType =
-          DirectoryServer.getDefaultAttributeType("changenumber");
-    Attribute a = Attributes.create("changenumber",
-        String.valueOf(draftChangenumber));
+    if((aType = DirectoryServer.getAttributeType("changenumber")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("changenumber");
+    a = Attributes.create("changenumber", String.valueOf(draftChangenumber));
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     //
-    if((attributeType =
-      DirectoryServer.getAttributeType("changetime")) == null)
-      attributeType =
-          DirectoryServer.getDefaultAttributeType("changetime");
+    if((aType = DirectoryServer.getAttributeType("changetime")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("changetime");
     SimpleDateFormat dateFormat;
     dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
     dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); // ??
-    a = Attributes.create(attributeType,
+    a = Attributes.create(aType,
         dateFormat.format(new Date(changeNumber.getTime())));
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     /* Change time in a friendly format
     Date date = new Date(changeNumber.getTime());
@@ -975,77 +1081,65 @@
      */
 
     //
-    if((attributeType =
-      DirectoryServer.getAttributeType("changetype")) == null)
-      attributeType =
-          DirectoryServer.getDefaultAttributeType("changetype");
-    a = Attributes.create(attributeType, changetype);
+    if((aType = DirectoryServer.getAttributeType("changetype")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("changetype");
+    a = Attributes.create(aType, changetype);
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     //
-    if((attributeType =
-      DirectoryServer.getAttributeType("targetdn")) == null)
-      attributeType =
-          DirectoryServer.getDefaultAttributeType("targetdn");
-    a = Attributes.create(attributeType,
-        targetDN.toNormalizedString());
+    if((aType = DirectoryServer.getAttributeType("targetdn")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("targetdn");
+    a = Attributes.create(aType, targetDN.toNormalizedString());
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     // NON REQUESTED attributes
 
-    if((attributeType =
-            DirectoryServer.getAttributeType("replicationcsn")) == null)
-        attributeType =
-                DirectoryServer.getDefaultAttributeType("replicationcsn");
-    a = Attributes.create(attributeType, changeNumber.toString());
+    if((aType = DirectoryServer.getAttributeType("replicationcsn")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("replicationcsn");
+    a = Attributes.create(aType, changeNumber.toString());
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     //
-    if((attributeType =
-      DirectoryServer.getAttributeType("replicaidentifier")) == null)
-      attributeType =
-          DirectoryServer.getDefaultAttributeType("replicaidentifier");
-    a = Attributes.create(attributeType,
-        Integer.toString(changeNumber.getServerId()));
+    if((aType = DirectoryServer.getAttributeType("replicaidentifier")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("replicaidentifier");
+    a = Attributes.create(aType, Integer.toString(changeNumber.getServerId()));
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     if (clearLDIFchanges != null)
     {
       if (changetype.equals("add"))
       {
-        if((attributeType =
-          DirectoryServer.getAttributeType("changes")) == null)
-          attributeType =
-            DirectoryServer.getDefaultAttributeType("changes");
+        if((aType = DirectoryServer.getAttributeType("changes")) == null)
+          aType = DirectoryServer.getDefaultAttributeType("changes");
 
-        a = Attributes.create(attributeType, clearLDIFchanges + "\n");
+        a = Attributes.create(aType, clearLDIFchanges + "\n");
         // force base64
         attrList = new ArrayList<Attribute>(1);
         attrList.add(a);
-        if(attributeType.isOperational())
-          operationalAttrs.put(attributeType, attrList);
+        if(aType.isOperational())
+          operationalAttrs.put(aType, attrList);
         else
-          uAttrs.put(attributeType, attrList);
+          uAttrs.put(aType, attrList);
 
         pattern = "creatorsName: ";
         try
@@ -1058,17 +1152,17 @@
             String creatorsName =
               clearLDIFchanges.substring(start_val_cr+2, end_val_cr);
 
-            if((attributeType =
+            if((aType =
               DirectoryServer.getAttributeType("changeInitiatorsName")) == null)
-              attributeType =
+              aType =
                 DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
-            a = Attributes.create(attributeType, creatorsName);
+            a = Attributes.create(aType, creatorsName);
             attrList = new ArrayList<Attribute>(1);
             attrList.add(a);
-            if(attributeType.isOperational())
-              operationalAttrs.put(attributeType, attrList);
+            if(aType.isOperational())
+              operationalAttrs.put(aType, attrList);
             else
-              uAttrs.put(attributeType, attrList);
+              uAttrs.put(aType, attrList);
           }
         }
         catch(Exception e)
@@ -1084,19 +1178,17 @@
       {
         if (changetype.equals("modify"))
         {
-          if((attributeType =
-            DirectoryServer.getAttributeType("changes")) == null)
-            attributeType =
-              DirectoryServer.getDefaultAttributeType("changes");
+          if((aType = DirectoryServer.getAttributeType("changes")) == null)
+            aType = DirectoryServer.getDefaultAttributeType("changes");
 
-          a = Attributes.create(attributeType, clearLDIFchanges + "\n");
+          a = Attributes.create(aType, clearLDIFchanges + "\n");
           // force base64
           attrList = new ArrayList<Attribute>(1);
           attrList.add(a);
-          if(attributeType.isOperational())
-            operationalAttrs.put(attributeType, attrList);
+          if(aType.isOperational())
+            operationalAttrs.put(aType, attrList);
           else
-            uAttrs.put(attributeType, attrList);
+            uAttrs.put(aType, attrList);
         }
 
         pattern = "modifiersName: ";
@@ -1110,17 +1202,17 @@
             String modifiersName =
               clearLDIFchanges.substring(start_val_cr, end_val_cr);
 
-            if((attributeType =
+            if((aType =
               DirectoryServer.getAttributeType("changeInitiatorsName")) == null)
-              attributeType =
+              aType =
                 DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
-            a = Attributes.create(attributeType, modifiersName);
+            a = Attributes.create(aType, modifiersName);
             attrList = new ArrayList<Attribute>(1);
             attrList.add(a);
-            if(attributeType.isOperational())
-              operationalAttrs.put(attributeType, attrList);
+            if(aType.isOperational())
+              operationalAttrs.put(aType, attrList);
             else
-              uAttrs.put(attributeType, attrList);
+              uAttrs.put(aType, attrList);
           }
         }
         catch(Exception e)
@@ -1136,40 +1228,35 @@
 
     if (changetype.equals("delete") && (delInitiatorsName!=null))
     {
-      if((attributeType =
-        DirectoryServer.getAttributeType("changeInitiatorsName")) == null)
-        attributeType =
-          DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
-      a = Attributes.create(attributeType, delInitiatorsName);
+      if((aType = DirectoryServer.getAttributeType("changeInitiatorsName"))
+          == null)
+        aType = DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
+      a = Attributes.create(aType, delInitiatorsName);
       attrList = new ArrayList<Attribute>(1);
       attrList.add(a);
-      if(attributeType.isOperational())
-        operationalAttrs.put(attributeType, attrList);
+      if(aType.isOperational())
+        operationalAttrs.put(aType, attrList);
       else
-        uAttrs.put(attributeType, attrList);
+        uAttrs.put(aType, attrList);
     }
 
     if (targetUUID != null)
     {
-      if((attributeType =
-        DirectoryServer.getAttributeType("targetentryuuid")) == null)
-        attributeType =
-            DirectoryServer.getDefaultAttributeType("targetentryuuid");
-      a = Attributes.create(attributeType, targetUUID);
+      if((aType = DirectoryServer.getAttributeType("targetentryuuid")) == null)
+        aType = DirectoryServer.getDefaultAttributeType("targetentryuuid");
+      a = Attributes.create(aType, targetUUID);
       attrList = new ArrayList<Attribute>(1);
       attrList.add(a);
-      if(attributeType.isOperational())
-        operationalAttrs.put(attributeType, attrList);
+      if(aType.isOperational())
+        operationalAttrs.put(aType, attrList);
       else
-        uAttrs.put(attributeType, attrList);
+        uAttrs.put(aType, attrList);
 
       if (draftChangenumber>0)
       {
         // compat mode
-        if((attributeType =
-          DirectoryServer.getAttributeType("targetuniqueid")) == null)
-          attributeType =
-              DirectoryServer.getDefaultAttributeType("targetuniqueid");
+        if((aType = DirectoryServer.getAttributeType("targetuniqueid")) == null)
+          aType = DirectoryServer.getDefaultAttributeType("targetuniqueid");
         String dseeValue = null;
         try
         {
@@ -1191,28 +1278,26 @@
         // or not return this entry.
         if (dseeValue != null)
         {
-          a = Attributes.create(attributeType, dseeValue);
+          a = Attributes.create(aType, dseeValue);
           attrList = new ArrayList<Attribute>(1);
           attrList.add(a);
-          if(attributeType.isOperational())
-            operationalAttrs.put(attributeType, attrList);
+          if(aType.isOperational())
+            operationalAttrs.put(aType, attrList);
           else
-            uAttrs.put(attributeType, attrList);
+            uAttrs.put(aType, attrList);
         }
       }
     }
 
-    if((attributeType =
-      DirectoryServer.getAttributeType("changelogcookie")) == null)
-      attributeType =
-          DirectoryServer.getDefaultAttributeType("changelogcookie");
-    a = Attributes.create(attributeType, cookie);
+    if((aType = DirectoryServer.getAttributeType("changelogcookie")) == null)
+      aType = DirectoryServer.getDefaultAttributeType("changelogcookie");
+    a = Attributes.create(aType, cookie);
     attrList = new ArrayList<Attribute>(1);
     attrList.add(a);
-    if(attributeType.isOperational())
-      operationalAttrs.put(attributeType, attrList);
+    if(aType.isOperational())
+      operationalAttrs.put(aType, attrList);
     else
-      uAttrs.put(attributeType, attrList);
+      uAttrs.put(aType, attrList);
 
     if (histEntryAttributes != null)
     {

--
Gitblit v1.10.0