@Override
    @FFDCIgnore(InvalidNameException.class)
    public Root search(Root root) throws WIMException {
        final String METHODNAME = "search";
        boolean bFirstChangeSearchCall = false;

        String searchExpr = null;

        Map<String, Control> ctrlMap = ControlsHelper.getControlMap(root);

        // Extract the cache control
        CacheControl cacheCtrl = (CacheControl) ctrlMap.get(SchemaConstants.DO_CACHE_CONTROL);

        // 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 log it as not supported
            else if (cacheMode != null && SchemaConstants.CACHE_MODE_CLEAR_ENTITY.equalsIgnoreCase(cacheMode)) {
                if (tc.isWarningEnabled())
                    Tr.warning(tc, WIMMessageKey.UNSUPPORTED_CLEAR_CACHE_MODE, WIMMessageHelper.generateMsgParms(reposId, cacheMode));
            } else if (tc.isWarningEnabled())
                Tr.warning(tc, WIMMessageKey.UNKNOWN_CLEAR_CACHE_MODE, WIMMessageHelper.generateMsgParms(reposId, cacheMode));
        }

        // Check whether this is a search for changed entities
        boolean bChangeSearch = true;
        SearchControl searchControl = (ChangeControl) ctrlMap.get(SchemaConstants.DO_CHANGE_CONTROL);
        if (searchControl == null) {
            bChangeSearch = false;
            searchControl = (SearchControl) ctrlMap.get(SchemaConstants.DO_SEARCH_CONTROL);
        } else {
            List<CheckPointType> checkpoint = ((ChangeControl) searchControl).getCheckPoint();
            if (checkpoint.size() == 0) {
                bFirstChangeSearchCall = true;
            }
        }
        if (searchControl != null) {
            searchExpr = searchControl.getExpression();
            if (!bFirstChangeSearchCall) {
                if (searchExpr == null || searchExpr.length() == 0) {
                    throw new SearchControlException(WIMMessageKey.MISSING_SEARCH_EXPRESSION, Tr.formatMessage(
                                                                                                               tc,
                                                                                                               WIMMessageKey.MISSING_SEARCH_EXPRESSION,
                                                                                                               null));
                }
            }
        }
        // Check if the base entries were specified by the client
        // If specified by client, then don't override them with entity search base
        Set<String> realms = getSpecifiedRealms(root);
        boolean isSearchBaseSetByClient = realms.contains("n/a"); // Indicates search bases were set by client

        // read the custom property allowDNPrincipalNameAsLiteral
        String customProperty = getContextProperty(root, SchemaConstants.ALLOW_DN_PRINCIPALNAME_AS_LITERAL);
        boolean ignoreDNBaseSearch = customProperty.equalsIgnoreCase("true");

        LdapSearchControl srchCtrl = getLdapSearchControl(searchControl, isSearchBaseSetByClient, ignoreDNBaseSearch);

        String[] searchBases = srchCtrl.getBases();
        String sFilter = srchCtrl.getFilter();
        int countLimit = srchCtrl.getCountLimit();
        int timeLimit = srchCtrl.getTimeLimit();
        List<String> entityTypes = srchCtrl.getEntityTypes();
        List<String> propNames = srchCtrl.getPropertyNames();
        int scope = srchCtrl.getScope();

        Root outRoot = new Root();

        if (bChangeSearch) {

            ChangeControl changeControl = (ChangeControl) searchControl;

            /*
             * It is possible that we retrieve changes since the specified checkpoint and
             * while we process them more changes occur in the repository. As a result if
             * current checkpoint is retrieved after processing the changed entries, we
             * may lose some changes. Hence, we need to first retrieve the current checkpoint
             * and then process changed entities.
             */

            // Get the current checkpoint
            String checkPoint = changeHandler.getCurrentCheckPoint();

            CheckPointType currCheckPointDO = new CheckPointType();
            currCheckPointDO.setRepositoryId(reposId);
            currCheckPointDO.setRepositoryCheckPoint(checkPoint);

            ChangeResponseControl changeResponseCtrl = new ChangeResponseControl();
            changeResponseCtrl.getCheckPoint().add(currCheckPointDO);

            // Get changed entities since the checkpoint specified in ChangeControl
            List<CheckPointType> checkPointList = changeControl.getCheckPoint();

            if ((checkPointList != null) && (checkPointList.size() > 0)) {
                /*
                 * At the adapter level, only the checkpoint corresponding to this
                 * repository is expected to be in the ChangeControl. Hence no need
                 * to check for repository ID
                 */
                CheckPointType checkPointDO = checkPointList.get(0);
                checkPoint = checkPointDO.getRepositoryCheckPoint();
                if (checkPoint == null) {
                    throw new ChangeControlException(WIMMessageKey.NULL_CHECKPOINT_VALUE, Tr.formatMessage(
                                                                                                           tc,
                                                                                                           WIMMessageKey.NULL_CHECKPOINT_VALUE,
                                                                                                           null));
                }

                boolean isAttrCacheNotEmpty = true;
                List<String> changeTypes = changeControl.getChangeTypes();
                for (int i = 0; i < searchBases.length; i++) {
                    List<LdapEntry> ldapEntriesList = changeHandler.searchChangedEntities(checkPoint, changeTypes, searchBases[i],
                                                                                          sFilter, scope, entityTypes, propNames, countLimit, timeLimit);

                    if (ldapEntriesList != null) {
                        for (int j = 0; j < ldapEntriesList.size(); j++) {
                            LdapEntry entry = ldapEntriesList.get(j);
                            // invalidating the attribute cache
                            // checking for active directory so as to check if it is a deleted change type the fetch the DN from the unique name
                            if (isActiveDirectory) {
                                if (SchemaConstants.CHANGETYPE_DELETE.equalsIgnoreCase(entry.getChangeType())) {
                                    iLdapConn.invalidateAttributes(iLdapConfigMgr.switchToLdapNode(entry.getUniqueName()), entry.getExtId(), entry.getUniqueName());
                                } else {
                                    iLdapConn.invalidateAttributes(entry.getDN(), entry.getExtId(), entry.getUniqueName());
                                }
                            } else {
                                if (isAttrCacheNotEmpty) {//checking if attribute cache is invalidated.
                                    if (entry.getExtId() == null && SchemaConstants.CHANGETYPE_DELETE.equalsIgnoreCase(entry.getChangeType())) {
                                        iLdapConn.invalidateAttributeCache();// clear the cache if extId of deleted entry is not known
                                        isAttrCacheNotEmpty = false;
                                    } else {
                                        iLdapConn.invalidateAttributes(entry.getDN(), entry.getExtId(), entry.getUniqueName());
                                    }
                                }
                            }
                            createEntityFromLdapEntry(outRoot, SchemaConstants.DO_ENTITIES, entry, propNames);
                        }
                        // invalidating the search cache
                        if (ldapEntriesList.size() > 0) {
                            iLdapConn.invalidateSearchCache();
                        }
                    }
                }
            }
        } else {
            if (root.isSetContexts()) {
                String inputPattern = getContextProperty(root, SchemaConstants.USE_USER_FILTER_FOR_SEARCH);
                if (inputPattern != null && inputPattern.length() > 0) {
                    String dn = null;
                    try {
                        dn = new LdapName(inputPattern).toString();
                    } catch (InvalidNameException e) {
                        e.getMessage();
                    }
                    if (dn == null) {
                        Filter f = iLdapConfigMgr.getUserFilter();
                        if (f != null)
                            sFilter = f.prepare(inputPattern);
                    }
                } else {
                    // Check if group filter pattern is specified
                    inputPattern = getContextProperty(root, SchemaConstants.USE_GROUP_FILTER_FOR_SEARCH);
                    if (inputPattern != null && inputPattern.length() > 0) {
                        String dn = null;
                        try {
                            dn = new LdapName(inputPattern).toString();
                        } catch (InvalidNameException e) {
                            e.getMessage();
                        }
                        if (dn == null) {
                            Filter f = iLdapConfigMgr.getGroupFilter();
                            if (f != null)
                                sFilter = f.prepare(inputPattern);
                        }
                    }
                }
            }

            for (int i = 0; i < searchBases.length; i++) {
                Set<LdapEntry> ldapEntriesSet = iLdapConn.searchEntities(searchBases[i], sFilter, null, scope, entityTypes, propNames,
                                                                         false, false, countLimit, timeLimit);
                for (LdapEntry entry : ldapEntriesSet) {
                    createEntityFromLdapEntry(outRoot, SchemaConstants.DO_ENTITIES, entry, propNames);
                }
            }
        }

        return outRoot;
    }
@ Override @ FFDCIgnore ( InvalidNameException . class ) public Root search ( Root root ) throws WIMException { final String METHODNAME = "search" ; boolean bFirstChangeSearchCall = false ; String searchExpr = null ; Map < String , Control > ctrlMap = ControlsHelper . getControlMap ( root ) ; CacheControl cacheCtrl = ( CacheControl ) ctrlMap . get ( SchemaConstants . DO_CACHE_CONTROL ) ; if ( cacheCtrl != null ) { String cacheMode = cacheCtrl . getMode ( ) ; if ( tc . isDebugEnabled ( ) ) { Tr . debug ( tc , METHODNAME + " Cache Control is passed with mode " + cacheMode ) ; } if ( cacheMode != null && SchemaConstants . CACHE_MODE_CLEARALL . equalsIgnoreCase ( cacheMode ) ) { iLdapConn . invalidateAttributeCache ( ) ; iLdapConn . invalidateSearchCache ( ) ; String uniqueName = getCallerUniqueName ( ) ; if ( tc . isWarningEnabled ( ) ) Tr . warning ( tc , WIMMessageKey . CLEAR_ALL_CLEAR_CACHE_MODE , WIMMessageHelper . generateMsgParms ( reposId , cacheMode , uniqueName ) ) ; } else if ( cacheMode != null && SchemaConstants . CACHE_MODE_CLEAR_ENTITY . equalsIgnoreCase ( cacheMode ) ) { if ( tc . isWarningEnabled ( ) ) Tr . warning ( tc , WIMMessageKey . UNSUPPORTED_CLEAR_CACHE_MODE , WIMMessageHelper . generateMsgParms ( reposId , cacheMode ) ) ; } else if ( tc . isWarningEnabled ( ) ) Tr . warning ( tc , WIMMessageKey . UNKNOWN_CLEAR_CACHE_MODE , WIMMessageHelper . generateMsgParms ( reposId , cacheMode ) ) ; } boolean bChangeSearch = true ; SearchControl searchControl = ( ChangeControl ) ctrlMap . get ( SchemaConstants . DO_CHANGE_CONTROL ) ; if ( searchControl == null ) { bChangeSearch = false ; searchControl = ( SearchControl ) ctrlMap . get ( SchemaConstants . DO_SEARCH_CONTROL ) ; } else { List < CheckPointType > checkpoint = ( ( ChangeControl ) searchControl ) . getCheckPoint ( ) ; if ( checkpoint . size ( ) == 0 ) { bFirstChangeSearchCall = true ; } } if ( searchControl != null ) { searchExpr = searchControl . getExpression ( ) ; if ( ! bFirstChangeSearchCall ) { if ( searchExpr == null || searchExpr . length ( ) == 0 ) { throw new SearchControlException ( WIMMessageKey . MISSING_SEARCH_EXPRESSION , Tr . formatMessage ( tc , WIMMessageKey . MISSING_SEARCH_EXPRESSION , null ) ) ; } } } Set < String > realms = getSpecifiedRealms ( root ) ; boolean isSearchBaseSetByClient = realms . contains ( "n/a" ) ; String customProperty = getContextProperty ( root , SchemaConstants . ALLOW_DN_PRINCIPALNAME_AS_LITERAL ) ; boolean ignoreDNBaseSearch = customProperty . equalsIgnoreCase ( "true" ) ; LdapSearchControl srchCtrl = getLdapSearchControl ( searchControl , isSearchBaseSetByClient , ignoreDNBaseSearch ) ; String [ ] searchBases = srchCtrl . getBases ( ) ; String sFilter = srchCtrl . getFilter ( ) ; int countLimit = srchCtrl . getCountLimit ( ) ; int timeLimit = srchCtrl . getTimeLimit ( ) ; List < String > entityTypes = srchCtrl . getEntityTypes ( ) ; List < String > propNames = srchCtrl . getPropertyNames ( ) ; int scope = srchCtrl . getScope ( ) ; Root outRoot = new Root ( ) ; if ( bChangeSearch ) { ChangeControl changeControl = ( ChangeControl ) searchControl ; String checkPoint = changeHandler . getCurrentCheckPoint ( ) ; CheckPointType currCheckPointDO = new CheckPointType ( ) ; currCheckPointDO . setRepositoryId ( reposId ) ; currCheckPointDO . setRepositoryCheckPoint ( checkPoint ) ; ChangeResponseControl changeResponseCtrl = new ChangeResponseControl ( ) ; changeResponseCtrl . getCheckPoint ( ) . add ( currCheckPointDO ) ; List < CheckPointType > checkPointList = changeControl . getCheckPoint ( ) ; if ( ( checkPointList != null ) && ( checkPointList . size ( ) > 0 ) ) { CheckPointType checkPointDO = checkPointList . get ( 0 ) ; checkPoint = checkPointDO . getRepositoryCheckPoint ( ) ; if ( checkPoint == null ) { throw new ChangeControlException ( WIMMessageKey . NULL_CHECKPOINT_VALUE , Tr . formatMessage ( tc , WIMMessageKey . NULL_CHECKPOINT_VALUE , null ) ) ; } boolean isAttrCacheNotEmpty = true ; List < String > changeTypes = changeControl . getChangeTypes ( ) ; for ( int i = 0 ; i < searchBases . length ; i ++ ) { List < LdapEntry > ldapEntriesList = changeHandler . searchChangedEntities ( checkPoint , changeTypes , searchBases [ i ] , sFilter , scope , entityTypes , propNames , countLimit , timeLimit ) ; if ( ldapEntriesList != null ) { for ( int j = 0 ; j < ldapEntriesList . size ( ) ; j ++ ) { LdapEntry entry = ldapEntriesList . get ( j ) ; if ( isActiveDirectory ) { if ( SchemaConstants . CHANGETYPE_DELETE . equalsIgnoreCase ( entry . getChangeType ( ) ) ) { iLdapConn . invalidateAttributes ( iLdapConfigMgr . switchToLdapNode ( entry . getUniqueName ( ) ) , entry . getExtId ( ) , entry . getUniqueName ( ) ) ; } else { iLdapConn . invalidateAttributes ( entry . getDN ( ) , entry . getExtId ( ) , entry . getUniqueName ( ) ) ; } } else { if ( isAttrCacheNotEmpty ) { if ( entry . getExtId ( ) == null && SchemaConstants . CHANGETYPE_DELETE . equalsIgnoreCase ( entry . getChangeType ( ) ) ) { iLdapConn . invalidateAttributeCache ( ) ; isAttrCacheNotEmpty = false ; } else { iLdapConn . invalidateAttributes ( entry . getDN ( ) , entry . getExtId ( ) , entry . getUniqueName ( ) ) ; } } } createEntityFromLdapEntry ( outRoot , SchemaConstants . DO_ENTITIES , entry , propNames ) ; } if ( ldapEntriesList . size ( ) > 0 ) { iLdapConn . invalidateSearchCache ( ) ; } } } } } else { if ( root . isSetContexts ( ) ) { String inputPattern = getContextProperty ( root , SchemaConstants . USE_USER_FILTER_FOR_SEARCH ) ; if ( inputPattern != null && inputPattern . length ( ) > 0 ) { String dn = null ; try { dn = new LdapName ( inputPattern ) . toString ( ) ; } catch ( InvalidNameException e ) { e . getMessage ( ) ; } if ( dn == null ) { Filter f = iLdapConfigMgr . getUserFilter ( ) ; if ( f != null ) sFilter = f . prepare ( inputPattern ) ; } } else { inputPattern = getContextProperty ( root , SchemaConstants . USE_GROUP_FILTER_FOR_SEARCH ) ; if ( inputPattern != null && inputPattern . length ( ) > 0 ) { String dn = null ; try { dn = new LdapName ( inputPattern ) . toString ( ) ; } catch ( InvalidNameException e ) { e . getMessage ( ) ; } if ( dn == null ) { Filter f = iLdapConfigMgr . getGroupFilter ( ) ; if ( f != null ) sFilter = f . prepare ( inputPattern ) ; } } } } for ( int i = 0 ; i < searchBases . length ; i ++ ) { Set < LdapEntry > ldapEntriesSet = iLdapConn . searchEntities ( searchBases [ i ] , sFilter , null , scope , entityTypes , propNames , false , false , countLimit , timeLimit ) ; for ( LdapEntry entry : ldapEntriesSet ) { createEntityFromLdapEntry ( outRoot , SchemaConstants . DO_ENTITIES , entry , propNames ) ; } } } return outRoot ; }
Method to perform a search on the underlying repository based on the specified search criteria

@param root The incoming Root object.