docs: @Override
      public Root get(Root root) throws WIMException {
          final String METHODNAME = "get";
          Root outRoot = new Root();
  
          Map<String, Control> ctrlMap = ControlsHelper.getControlMap(root);
          PropertyControl propertyCtrl = (PropertyControl) ctrlMap.get(SchemaConstants.DO_PROPERTY_CONTROL);
          GroupMembershipControl grpMbrshipCtrl = (GroupMembershipControl) ctrlMap.get(SchemaConstants.DO_GROUP_MEMBERSHIP_CONTROL);
          GroupMemberControl grpMbrCtrl = (GroupMemberControl) ctrlMap.get(SchemaConstants.DO_GROUP_MEMBER_CONTROL);
          AncestorControl ancesCtrl = (AncestorControl) ctrlMap.get(SchemaConstants.DO_ANCESTOR_CONTROL);
          DescendantControl descCtrl = (DescendantControl) ctrlMap.get(SchemaConstants.DO_DESCENDANT_CONTROL);
          CheckGroupMembershipControl chkGrpMbrshipCtrl = (CheckGroupMembershipControl) ctrlMap.get(SchemaConstants.DO_CHECK_GROUP_MEMBERSHIP_CONTROL);
          CacheControl cacheCtrl = (CacheControl) ctrlMap.get(SchemaConstants.DO_CACHE_CONTROL);
  
          boolean clearCacheForMembership = false;
  
          // If a cache control is passed, the cache should be cleared
          if (cacheCtrl != null) {
              String cacheMode = cacheCtrl.getMode();
              if (tc.isDebugEnabled())
                  Tr.debug(tc, METHODNAME + " Cache Control is passed with mode " + cacheMode);
  
              // If the mode is 'clearAll', then invalidate the caches
              if (cacheMode != null && SchemaConstants.CACHE_MODE_CLEARALL.equalsIgnoreCase(cacheMode)) {
                  // Invalidate the attributes cache
                  iLdapConn.invalidateAttributeCache();
  
                  // Invalidate the search cache
                  iLdapConn.invalidateSearchCache();
  
                  // Log this clearAll call
                  String uniqueName = getCallerUniqueName();
                  if (tc.isWarningEnabled())
                      Tr.warning(tc, WIMMessageKey.CLEAR_ALL_CLEAR_CACHE_MODE, WIMMessageHelper.generateMsgParms(reposId, cacheMode, uniqueName));
              }
  
              // If the mode is 'clearEntity', then invalidate the attribute cache for the DN
              else if (cacheMode != null && SchemaConstants.CACHE_MODE_CLEAR_ENTITY.equalsIgnoreCase(cacheMode)) {
                  // Get the entities
                  List<Entity> entities = root.getEntities();
  
                  // Iterate over the entities and remove each one from the cache.
                  for (Entity inEntity : entities) {
                      // Get the identifier
                      IdentifierType id = inEntity.getIdentifier();
                      String externalName = id.getExternalName();
                      String extId = id.getExternalId();
                      String uniqueName = id.getUniqueName();
  
                      // Invalidate attibutes
                      iLdapConn.invalidateAttributes(externalName, extId, uniqueName);
                  }
  
                  // Set the flag that would be used to determine if the search
                  // cache needs to be cleared later, depending on whether
                  // the user has passed the Group Member and/or Group Membership controls.
                  clearCacheForMembership = true;
              } else if (tc.isWarningEnabled())
                  Tr.warning(tc, WIMMessageKey.UNKNOWN_CLEAR_CACHE_MODE, WIMMessageHelper.generateMsgParms(reposId, cacheMode));
          }
  
          List<String> propNames = null;
          if (propertyCtrl != null) {
              propNames = propertyCtrl.getProperties();
          }
          boolean needMbrAttr = false;
  
          if (grpMbrCtrl != null
              && (iLdapConfigMgr.getMembershipAttribute() == null || !iLdapConfigMgr.isDefaultMbrAttr())) {
              needMbrAttr = true;
          }
  
          for (Entity inEntity : root.getEntities()) {
              String inEntityType = inEntity.getTypeName();
              List<String> properties = iLdapConfigMgr.getSupportedProperties(inEntityType, propNames);
  
              List<String> EntityType = new ArrayList<String>(1);
              EntityType.add(inEntityType);
  
              IdentifierType inId = inEntity.getIdentifier();
  
              // Only retrieve member attr when there grpMbrCtrl is not null and no grpMbrship attr.
              LdapEntry ldapEntry = iLdapConn.getEntityByIdentifier(inId, EntityType, properties,
                                                                    (grpMbrshipCtrl != null || chkGrpMbrshipCtrl != null), needMbrAttr);
  
              // New:: Change to Input/Output property <<START>>
              if (ldapEntry != null && propNames != null) {
                  if (propNames.contains(SchemaConstantsInternal.PROP_DISPLAY_BRIDGE_PRINCIPAL_NAME)) {
                      String type = ldapEntry.getType();
                      LdapEntity entity = iLdapConfigMgr.getLdapEntity(type);
                      String attrName = entity.getAttribute(SchemaConstants.PROP_PRINCIPAL_NAME);
                      String[] attrIds = new String[] { attrName };
                      ArrayList<String> entityTypes = new ArrayList<String>(1);
                      entityTypes.add(type);
                      Attributes attrs = iLdapConn.getAttributesByUniqueName(ldapEntry.getUniqueName(), attrIds, entityTypes);
                      if (attrs != null) {
                          NamingEnumeration<? extends Attribute> attEnum = attrs.getAll();
                          while (attEnum.hasMoreElements()) {
                              try {
                                  ldapEntry.getAttributes().put(attEnum.next());
                              } catch (NamingException e) {
                                  /* Ignore. */
                              }
                          }
                      }
  
                      if (properties != null)
                          properties.add(SchemaConstants.PROP_PRINCIPAL_NAME);
                      else {
                          properties = new ArrayList<String>();
                          properties.add(SchemaConstants.PROP_PRINCIPAL_NAME);
                      }
                  } else if (propNames.contains(SchemaConstantsInternal.PROP_DISPLAY_BRIDGE_CN)) {
                      String type = ldapEntry.getType();
                      LdapEntity entity = iLdapConfigMgr.getLdapEntity(type);
                      String attrName = entity.getAttribute("cn");
                      String[] attrIds = new String[] { attrName };
                      ArrayList<String> entityTypes = new ArrayList<String>(1);
                      entityTypes.add(type);
                      Attributes attrs = iLdapConn.getAttributesByUniqueName(ldapEntry.getUniqueName(), attrIds, entityTypes);
                      if (attrs != null) {
                          NamingEnumeration<? extends Attribute> attEnum = attrs.getAll();
                          while (attEnum.hasMoreElements()) {
                              try {
                                  ldapEntry.getAttributes().put(attEnum.next());
                              } catch (NamingException e) {
                                  /* Ignore. */
                              }
                          }
                      }
  
                      if (properties != null)
                          properties.add("cn");
                      else {
                          properties = new ArrayList<String>();
                          properties.add("cn");
                      }
                  }
              }
              // New:: Change to Input/Output property <<END>>
  
              Entity outEntity = createEntityFromLdapEntry(outRoot, SchemaConstants.DO_ENTITIES, ldapEntry, properties);
  
              // If Cache needs to be cleared
              if (clearCacheForMembership) {
                  // If fetched entity is a group
                  if (iLdapConfigMgr.isGroup(ldapEntry.getType())) {
                      // If group member control is passed, clear the search cache.
                      // This is done in order to correctly fetch members of dynamic groups.
                      if (grpMbrCtrl != null)
                          iLdapConn.invalidateSearchCache();
                      // If the membership control is passed, clear the search cache as the membership will be determined
                      // by a search
                      if ((grpMbrshipCtrl != null || chkGrpMbrshipCtrl != null))
                          iLdapConn.invalidateSearchCache();
                  }
                  // If fetched entity is a person or person account
                  else if (iLdapConfigMgr.isPerson(ldapEntry.getType()) || iLdapConfigMgr.isPersonAccount(ldapEntry.getType())) {
                      // If the membership control is passed.
                      if ((grpMbrshipCtrl != null || chkGrpMbrshipCtrl != null)) {
                          // If membership attribute is not specified, clear the search cache.
                          if (iLdapConfigMgr.getMembershipAttribute() != null) {
                              String mbrshipAttrName = iLdapConfigMgr.getMembershipAttribute();
                              Attribute mbrshipAttr = ldapEntry.getAttributes().get(mbrshipAttrName);
                              try {
                                  // If membership attr is not found
                                  if (mbrshipAttr == null || (mbrshipAttr.size() == 1 && mbrshipAttr.get(0) == null)) {
                                      iLdapConn.invalidateSearchCache();
                                  }
  
                                  // If membership attr does not include dynamic groups i.e. the membership attribute is defined but its scope is not "All"
                                  // or if the membership attribute does not support dynamic groups, then the search results cache need to be cleared.
                                  if (iLdapConfigMgr.getMembershipAttributeScope() != LDAP_ALL_GROUP_MEMBERSHIP && iLdapConfigMgr.supportDynamicGroup()) {
                                      iLdapConn.invalidateSearchCache();
                                  }
                              } catch (NamingException e) {
                                  // If there was any exception in fetching the attributes, clear the search results cache.
                                  iLdapConn.invalidateSearchCache();
                              }
                          } else {
                              // If membership attribute is not defined, then clear the search results cache.
                              iLdapConn.invalidateSearchCache();
                          }
                      }
                  }
              }
  
              // Retrieve groups
              getGroups(outEntity, ldapEntry, grpMbrshipCtrl);
  
              // Retrieve members if this is a group
              if (iLdapConfigMgr.isGroup(ldapEntry.getType())) {
                  getMembers(outEntity, ldapEntry, grpMbrCtrl);
              }
  
              // Retrieve descendants
              getDescendants(outEntity, ldapEntry, descCtrl);
  
              // Retrieve ancestors
              getAncestors(outEntity, ldapEntry, ancesCtrl);
  
              if (chkGrpMbrshipCtrl != null) {
                  int level = chkGrpMbrshipCtrl.getLevel();
                  CheckGroupMembershipControl reChkCtrl = new CheckGroupMembershipControl();
                  reChkCtrl.setInGroup(isMemberInGroup(inEntity, ldapEntry, level));
              }
          }
  
          return outRoot;
      }