docs: @SuppressWarnings("unchecked")
      @Override
      @FFDCIgnore({ EntryNotFoundException.class, RegistryException.class })
      public Root search(Root root) throws WIMException {
          final String METHODNAME = "search";
          String uniqueName = null;
          Root returnRoot = new Root();
  
          AuditManager auditManager = new AuditManager();
  
          List<Entity> entitys = root.getEntities();
          if (entitys != null && !entitys.isEmpty()) {
              Entity entitee = entitys.get(0);
              if (entitee != null) {
                  IdentifierType identifier = entitee.getIdentifier();
                  if (identifier != null)
                      uniqueName = identifier.getUniqueName();
              }
          }
  
          try {
              int countLimit = 0;
  
              Map<String, Control> ctrlMap = ControlsHelper.getControlMap(root);
              SearchControl searchControl = (SearchControl) ctrlMap.get(SchemaConstants.DO_SEARCH_CONTROL);
  
              if (searchControl.isSetCountLimit()) {
                  countLimit = searchControl.getCountLimit();
              }
  
              String expression = searchControl.getExpression();
              if (expression == null || expression.trim().length() == 0) {
                  Audit.audit(Audit.EventID.SECURITY_MEMBER_MGMT_01, auditManager.getRESTRequest(), AuditConstants.SEARCH_AUDIT, reposId, uniqueName,
                              userRegistry.getRealm(),
                              returnRoot,
                              Integer.valueOf("217"), AuditConstants.URBRIDGE);
                  throw new SearchControlException(WIMMessageKey.MISSING_SEARCH_EXPRESSION, Tr.formatMessage(tc, WIMMessageKey.MISSING_SEARCH_EXPRESSION));
              }
  
              URBridgeXPathHelper xpathHelper = new URBridgeXPathHelper(expression);
              expression = xpathHelper.getExpression();
  
              boolean returnSubType = searchControl.isReturnSubType();
              List<String> entityTypes = xpathHelper.getEntityTypes();
              Set<String> entityTypeSet = new HashSet<String>();
              List<String> entityTypeList = null;
  
              if (returnSubType) {
                  for (int i = 0; i < entityTypes.size(); i++) {
                      String type = entityTypes.get(i);
                      Set<String> subTypes = Entity.getSubEntityTypes(type);
                      entityTypeSet.add(type);
                      if (subTypes != null) {
                          entityTypeSet.addAll(subTypes);
                      }
                  }
              } else {
                  entityTypeSet.addAll(entityTypes);
              }
              entityTypeList = new ArrayList<String>(entityTypeSet);
  
              if (tc.isDebugEnabled())
                  Tr.debug(tc, METHODNAME + " entityType List: " + entityTypeList);
  
              String type;
              for (int i = 0; i < entityTypeList.size(); i++) {
                  type = entityTypeList.get(i);
                  if (Service.DO_GROUP.equalsIgnoreCase(type) || Entity.getSubEntityTypes(Service.DO_GROUP).contains(type)) {
                      List<String> searchAttrs = getAttributes(searchControl, type);
                      List<String> returnNames = new ArrayList<String>();
  
                      if (isSafRegistry() && !expression.endsWith(SchemaConstants.VALUE_WILD_CARD)) {
                          try {
                              returnNames.add(userRegistry.getGroupSecurityName(expression));
                          } catch (EntryNotFoundException enfe) {
                          } catch (RegistryException re) {
                          }
                      } else {
                          if (!expression.contains(SchemaConstants.VALUE_WILD_CARD)) {
                              countLimit = 1;
                          }
  
                          returnNames = searchGroups(expression, countLimit).getList();
                      }
                      if (returnNames.size() > 0) {
                          URBridgeEntityFactory osEntityFactory = new URBridgeEntityFactory();
                          for (int j = 0; j < returnNames.size(); j++) {
                              Entity matchDO = null;
  
                              if (type.equalsIgnoreCase(Service.DO_PERSON_ACCOUNT))
                                  matchDO = new PersonAccount();
                              else
                                  matchDO = new Group();
  
                              returnRoot.getEntities().add(matchDO);
                              IdentifierType id = new IdentifierType();
                              matchDO.setIdentifier(id);
                              // Populate the entity with all requested attributes.
                              URBridgeEntity osEntity = osEntityFactory.createObject(matchDO, this, propsMap, baseEntryName,
                                                                                     entityConfigMap);
                              osEntity.setSecurityNameProp(returnNames.get(j));
                              osEntity.populateEntity(searchAttrs);
                              //set identifier
                              id.setRepositoryId(reposId);
                          }
                      }
                      break;
                  }
              }
              for (int i = 0; i < entityTypeList.size(); i++) {
                  type = entityTypeList.get(i);
                  if (Entity.getSubEntityTypes(Service.DO_LOGIN_ACCOUNT).contains(type)) {
                      List<String> searchAttrs = getAttributes(searchControl, type);
                      List<String> returnNames = new ArrayList<String>();
  
                      if (isSafRegistry() && !expression.endsWith(SchemaConstants.VALUE_WILD_CARD)) {
                          try {
                              returnNames.add(userRegistry.getUserSecurityName(expression));
                          } catch (EntryNotFoundException enfe) {
                          } catch (RegistryException re) {
                          }
                      } else {
                          if (!expression.contains(SchemaConstants.VALUE_WILD_CARD)) {
                              countLimit = 1;
                          }
                          returnNames = searchUsers(expression, countLimit).getList();
                      }
                      if (returnNames.size() > 0) {
                          URBridgeEntityFactory osEntityFactory = new URBridgeEntityFactory();
                          if (type.equalsIgnoreCase(Service.DO_LOGIN_ACCOUNT)) {
                              type = URBridgeHelper.getPersonAccountType();
                          }
  
                          for (int j = 0; j < returnNames.size(); j++) {
                              Entity matchDO = new PersonAccount();
                              returnRoot.getEntities().add(matchDO);
                              IdentifierType id = new IdentifierType();
                              matchDO.setIdentifier(id);
                              // Populate the entity with all requested attributes.
                              URBridgeEntity osEntity = osEntityFactory.createObject(matchDO, this, propsMap, baseEntryName,
                                                                                     entityConfigMap);
                              osEntity.setSecurityNameProp(returnNames.get(j));
                              osEntity.populateEntity(searchAttrs);
                              //set identifier
                              id.setRepositoryId(reposId);
                          }
                      }
                      break;
                  }
              }
          } catch (WIMException we) {
              throw we;
          } catch (Exception e) {
              Audit.audit(Audit.EventID.SECURITY_MEMBER_MGMT_01, auditManager.getRESTRequest(), AuditConstants.SEARCH_AUDIT, reposId, uniqueName, userRegistry.getRealm(),
                          returnRoot,
                          Integer.valueOf("221"), AuditConstants.URBRIDGE);
              throw new WIMApplicationException(WIMMessageKey.ENTITY_SEARCH_FAILED, Tr.formatMessage(tc, WIMMessageKey.ENTITY_SEARCH_FAILED,
                                                                                                     WIMMessageHelper.generateMsgParms(e.toString())));
          }
  
          if (returnRoot != null && !returnRoot.getEntities().isEmpty()) {
              auditManager.setRealm(userRegistry.getRealm());
              Audit.audit(Audit.EventID.SECURITY_MEMBER_MGMT_01, auditManager.getRESTRequest(), AuditConstants.SEARCH_AUDIT, reposId, uniqueName, userRegistry.getRealm(),
                          returnRoot,
                          Integer.valueOf("200"), AuditConstants.URBRIDGE);
          }
          return returnRoot;
      }