LDAP分页查询

来源:互联网 发布:进口数据 编辑:程序博客网 时间:2024/06/13 21:48

基于spring-ldap-core-1.3.1



public List<TestData> findTestData() throws  Exception{
        AndFilter filter = new AndFilter();
        filter.and(new GreaterThanOrEqualsFilter("filterCondition", "your filterCondition"));
        String baseNam = "";//这里可以指定为""或者你要查询的某个根目录, 如:cn=testdata
        
        List<TestData> list = new ArrayList<TestData>();
        //声明搜索控件
        SearchControls schCtrls = new SearchControls();
        // 返回属性设置  
        String[] returnAttrs = { "testName", "testTime", "testUser"};  
        schCtrls.setReturningAttributes(returnAttrs);
        //指定检索范围
        /*
         * 0:OBJECT_SCOPE,搜索指定的命名对象。  
         * 1:ONELEVEL_SCOPE,只搜索指定命名对象的一个级别,这是缺省值。
         * 2:SUBTREE_SCOPE,搜索以指定命名对象为根结点的整棵树  **/
        schCtrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        
        int pageSize = 500;  
        byte[] cookie = null;
        ContextSource contextSource = ldapTemplate.getContextSource();
        DirContext ctx = contextSource.getReadWriteContext();  
        LdapContext lCtx = (LdapContext) ctx;  
        //分页
        lCtx.setRequestControls(new Control[] { new PagedResultsControl(  pageSize, Control.CRITICAL) });
        int totalResults = 0;
        do {  
            //搜索的结果的枚举属性
            NamingEnumeration<SearchResult> results = lCtx.search(baseNam,  filter.toString(), schCtrls);  
            while (null != results && results.hasMoreElements()) {//结果不为空且有值  
                SearchResult sr = results.next();  
                Attributes attrs = sr.getAttributes();  
                TestData testData = dataConvert(attrs);
                list.add(testData);
                totalResults++;  
            }
            //cookie是一个字节数组,包含了通过PagedResultsControl下一次调用服务器时所需的信息
            cookie = parseControls(lCtx.getResponseControls());  
            lCtx.setRequestControls(new Control[] { new PagedResultsControl(  pageSize, cookie, Control.CRITICAL) });  
        } while ((cookie != null) && (cookie.length != 0));  
        lCtx.close();  
        System.out.println("Total = " + totalResults);  
        
        return list;
    }
    /**
     * 将LDAP的操作日志changlog转换成TestData对象
     * @param attrs
     * @return
     */
    private TestData dataConvert(Attributes attrs) {
        TestData testData = new TestData();
        Map<String, String> testDataMap = new HashMap<String, String>();// 查找TestData对象每个成员变量的类型,用于后续的数据转换
        Class objClass = testData.getClass();
        for (int i = 0; i < objClass.getDeclaredFields().length; i++)
        {
            Field field = objClass.getDeclaredFields()[i];
            if (field.getType().toString().endsWith("List"))
                testDataMap.put(field.getName(), "List");
            else
                testDataMap.put(field.getName(), "String");
        }
        
        testDataMap.put("reqMod", "List");

        NamingEnumeration results = attrs.getAll(); // 检索属性集中属性的枚举

        try
        {
            while (results.hasMoreElements())
            {
                Attribute attr = null;
                try
                {
                    attr = (Attribute) results.next(); // 检索枚举中的下一个元素
                } catch (NamingException e)
                {
                    e.printStackTrace();
                }             
                String attrValue = null;
                try
                {
                    attrValue = attr.get().toString(); // 检索此属性的其中一个值
                } catch (NamingException e)
                {
                    e.printStackTrace();
                }
                if (attrValue != null && attrValue.length() > 0)
                {
                    String attrName = attr.getID(); // 检索此属性的 id
                    List<String> list = new ArrayList<String>();
                    NamingEnumeration map = attr.getAll(); // 用于判断属性值是否为多值属性
                    
                    if (map != null)
                    {
                        while (map.hasMore())
                        {
                            String mod = map.next().toString();
                            list.add(mod);
                        }
                    }
                    if ("List".equals(testDataMap.get(attrName)))
                        BeanUtils.setProperty(testData, attrName, list);// 多值成员变量处理方式
                    else
                        BeanUtils.setProperty(testData, attrName, attrValue);// 单值成员变量处理方式

                }
            }

        } catch (Exception ex)
        {
            ex.printStackTrace();
        }
        
        return testData;
    }

    //下次查询要用的cookie
    private static byte[] parseControls(Control[] controls)  
            throws NamingException {  
        byte[] cookie = null;  
        if (controls != null) {  
            for (int i = 0; i < controls.length; i++) {  
                if (controls[i] instanceof PagedResultsResponseControl) {  
                    PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];  
                    cookie = prrc.getCookie();  
                    System.out.println(">>Next Page \n");  
                }  
            }  
        }  
        return (cookie == null) ? new byte[0] : cookie;  

    }


spring ldap配置:

<bean id="contextSource" class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy">
        <constructor-arg ref="pooledContextSource"/>
    </bean>

    <bean id="pooledContextSource" class="org.springframework.ldap.pool.factory.MutablePoolingContextSource">
        <property name="contextSource" ref="contextSourceTarget"/>
        <property name="dirContextValidator" ref="dirContextValidator"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testWhileIdle" value="true"/>
        <property name="minIdle" value="0"/>
        <property name="maxIdle" value="8"/>
        <property name="maxActive" value="8"/>
        <property name="maxTotal" value="100"/>
        <property name="maxWait" value="-1"/>
    </bean>
    <bean id="dirContextValidator" class="org.springframework.ldap.pool.validation.DefaultDirContextValidator"/>

<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="ldap://127.0.01:389" />
        <property name="userDn" value="cn=root,dc=testdata" />
        <property name="password" value="12345"/>
        <property name="pooled" value="false" />
    </bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="contextSource" />
    </bean>

<!-- 将ldapTemplate注入到testDataDao-->
    <bean id="testDataDao_LDAP" class="com.talkweb.mainSyn.dal.impl.TestDataDaoImpl">
        <property name="ldapTemplate">
            <ref bean="ldapTemplate" />
        </property>
    </bean>


参考资料: http://docs.spring.io/spring-ldap/docs/1.3.2.RELEASE/reference/html/pooling.html

                  http://blog.csdn.net/xufaxi/article/details/5840691

                  http://docs.spring.io/spring-ldap/docs/1.3.2.RELEASE/reference/html/index.html


-----------------------------------------------------------------------------------------------------------------------

9. Pooling Support

9.1. Introduction

Pooling LDAP connections helps mitigate the overhead ofcreating a new LDAP connection for each LDAP interaction.WhileJava LDAP pooling supportexists it is limited in its configuration options andfeatures, such as connection validation and poolmaintenance. Spring LDAP provides support for detailed poolconfiguration on a per-ContextSourcebasis.

Pooling support is provided byPoolingContextSourcewhich can wrap anyContextSourceand pool both read-only and read-writeDirContextobjects.Jakarta Commons-Poolis used to provide the underlying pool implementation.

9.2. DirContext Validation

Validation of pooled connections is the primary motivationfor using a custom pooling library versus the JDK providedLDAP pooling functionality. Validation allows pooledDirContextconnections to be checked to ensure they are still properlyconnected and configured when checking them out of the pool,in to the pool or while idle in the pool

TheDirContextValidatorinterface is used by thePoolingContextSourcefor validation andDefaultDirContextValidatoris provided as the default validation implementation.DefaultDirContextValidatordoes aDirContext.search(String, String, SearchControls), with an empty name, a filter of"objectclass=*"andSearchControlsset to limit a single result with the only the objectclassattribute and a 500ms timeout. If the returnedNamingEnumerationhas results theDirContextpasses validation, if no results are returned or anexception is thrown theDirContextfails validation. TheDefaultDirContextValidatorshould work with no configuration changes on most LDAPservers and provide the fastest way to validate theDirContext.

9.3. Pool Properties

The following properties are available on thePoolingContextSourcefor configuration of the DirContext pool. ThecontextSourceproperty must be set and thedirContextValidatorproperty must be set if validation is enabled, all otherproperties are optional.

Table 9.1. Pooling Configuration Properties

ParameterDefaultDescriptioncontextSourcenullTheContextSourceimplementation to getDirContexts from to populate the pool.dirContextValidatornullTheDirContextValidatorimplementation to use when validatingconnections. This is required iftestOnBorrow,testOnReturn, ortestWhileIdleoptions are set totrue.maxActive8The maximum number of active connections ofeach type (read-only|read-write) that can beallocated from this pool at the same time,or non-positive for no limit.maxTotal-1The overall maximum number of activeconnections (for all types) that can beallocated from this pool at the same time,or non-positive for no limit.maxIdle8The maximum number of active connections ofeach type (read-only|read-write) that canremain idle in the pool, without extra onesbeing released, or non-positive for nolimit.minIdle0The minimum number of active connections ofeach type (read-only|read-write) that canremain idle in the pool, without extra onesbeing created, or zero to create none.maxWait-1The maximum number of milliseconds that thepool will wait (when there are no availableconnections) for a connection to be returnedbefore throwing an exception, ornon-positive to wait indefinitely.whenExhaustedAction1 (BLOCK)Specifies the behaviour when the pool isexhausted.
  • TheFAIL (0)option will throw aNoSuchElementExceptionwhen the pool is exhausted.

  • The BLOCK (1) option will wait until a new object is available. IfmaxWait is positive aNoSuchElementExceptionis thrown if no new object is available after themaxWait time expires.

  • TheGROW (2)option will create and return anew object (essentially makingmaxActivemeaningless).

testOnBorrowfalseThe indication of whether objects will bevalidated before being borrowed from thepool. If the object fails to validate, itwill be dropped from the pool, and anattempt to borrow another will be made.testOnReturnfalseThe indication of whether objects will bevalidated before being returned to the pool.testWhileIdlefalseThe indication of whether objects will bevalidated by the idle object evictor (ifany). If an object fails to validate, itwill be dropped from the pool.timeBetweenEvictionRunsMillis-1The number of milliseconds to sleep betweenruns of the idle object evictor thread. Whennon-positive, no idle object evictor threadwill be run.numTestsPerEvictionRun3The number of objects to examine during eachrun of the idle object evictor thread (ifany).minEvictableIdleTimeMillis1000 * 60 * 30The minimum amount of time an object may sitidle in the pool before it is eligible foreviction by the idle object evictor (ifany).

9.4. Configuration

Configuring pooling should look very familiar if you're usedto Jakarta Commons-Pool or Commons-DBCP. You will firstcreate a normalContextSourcethen wrap it in aPoolingContextSource.

<beans>   ...   <bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">      <property name="contextSource" ref="contextSourceTarget" />   </bean>       <bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">      <property name="url" value="ldap://localhost:389" />      <property name="base" value="dc=example,dc=com" />      <property name="userDn" value="cn=Manager" />      <property name="password" value="secret" />      <property name="pooled" value="false"/>   </bean>   ...</beans>

In a real world example you would probably configure thepool options and enable connection validation; the aboveserves as an example to demonstrate the general idea.

[Note]Note

Ensure that thepooledproperty is set tofalseon anyContextSourcethat will be wrapped in aPoolingContextSource. ThePoolingContextSourcemust be able to create new connections when neededand ifpooledis set totruethat may not be possible.

[Note]Note

You'll notice that the actualContextSourcegets an id with a "Target" suffix. The bean you willactually refer to is thePoolingContextSourcethat wraps the targetcontextSource

9.4.1. Validation Configuration

Adding validation and a few pool configuration tweaks tothe above example is straight forward. Inject aDirContextValidatorand set when validation should occur and the pool isready to go.

<beans>   ...   <bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">      <property name="contextSource" ref="contextSourceTarget" />      <property name="dirContextValidator" ref="dirContextValidator" />      <property name="testOnBorrow" value="true" />      <property name="testWhileIdle" value="true" />   </bean>   <bean id="dirContextValidator"         class="org.springframework.ldap.pool.validation.DefaultDirContextValidator" />       <bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">      <property name="url" value="ldap://localhost:389" />      <property name="base" value="dc=example,dc=com" />      <property name="userDn" value="cn=Manager" />      <property name="password" value="secret" />      <property name="pooled" value="false"/>   </bean>   ...</beans>

The above example will test eachDirContextbefore it is passed to the client application and testDirContexts that have been sitting idle in the pool.

9.5. Known Issues

9.5.1. Custom Authentication

The PoolingContextSource assumes that all DirContext objects retrieved from ContextSource.getReadOnlyContext() will have the same environment and likewise that allDirContext objects retrieved fromContextSource.getReadWriteContext() will have the same environment. This means that wrapping aLdapContextSource configured with anAuthenticationSource in a PoolingContextSource will not function as expected. The pool would be populated using the credentials of the first user and unless new connections were needed subsequent context requests would not be filled for the user specified by the AuthenticationSource for the requesting thread.



0 0
原创粉丝点击