You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2008/12/14 14:53:56 UTC
svn commit: r726446 - in /directory/apacheds/trunk:
protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/SearchHandler.java
server-integ/src/test/java/org/apache/directory/server/operations/search/SearchLimitsIT.java
Author: elecharny
Date: Sun Dec 14 05:53:56 2008
New Revision: 726446
URL: http://svn.apache.org/viewvc?rev=726446&view=rev
Log:
Restored back the SizeLimit tests, and the simple search code. The PagedSearch are not yet working, but will soon.
Modified:
directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/SearchHandler.java
directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchLimitsIT.java
Modified: directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/SearchHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/SearchHandler.java?rev=726446&r1=726445&r2=726446&view=diff
==============================================================================
--- directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/SearchHandler.java (original)
+++ directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/SearchHandler.java Sun Dec 14 05:53:56 2008
@@ -69,6 +69,8 @@
import javax.naming.NamingException;
import javax.naming.ldap.PagedResultsControl;
+import static java.lang.Math.min;
+
/**
* A handler for processing search requests.
@@ -278,21 +280,52 @@
}
- private int getSearchSizeLimits( SearchRequest req, LdapSession session )
+ /**
+ * Return the server size limit
+ */
+ private int getServerSizeLimit( LdapSession session, SearchRequest request )
{
- LOG.debug( "req size limit = {}, configured size limit = {}", req.getSizeLimit(),
- ldapService.getMaxSizeLimit() );
-
- // Don't bother setting size limits for administrators that don't ask for it
- if ( session.getCoreSession().isAnAdministrator() && req.getSizeLimit() == NO_SIZE_LIMIT )
+ if ( session.getCoreSession().isAnAdministrator() )
{
- return Integer.MAX_VALUE;
+ if ( request.getSizeLimit() == NO_SIZE_LIMIT )
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return request.getSizeLimit();
+ }
+ }
+ else
+ {
+ if ( ldapService.getMaxSizeLimit() == NO_SIZE_LIMIT )
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return ldapService.getMaxSizeLimit();
+ }
}
+ }
+
+
+ private int getSearchSizeLimits( SearchRequest req, LdapSession session )
+ {
+ LOG.debug( "req size limit = {}, server size limit = {}", req.getSizeLimit(),
+ ldapService.getMaxSizeLimit() );
// Don't bother setting size limits for administrators that don't ask for it
if ( session.getCoreSession().isAnAdministrator() )
{
- return req.getSizeLimit();
+ if ( req.getSizeLimit() == NO_SIZE_LIMIT )
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return req.getSizeLimit();
+ }
}
/*
@@ -340,13 +373,14 @@
private SearchResponseDone readResults( LdapSession session, SearchRequest req,
- LdapResult ldapResult, EntryFilteringCursor cursor, int sizeLimit, boolean isPaged,
+ LdapResult ldapResult, EntryFilteringCursor cursor, int requestLimit, int serverLimit, boolean isPaged,
PagedSearchCookie cookieInstance, PagedResultsControl pagedResultsControl ) throws Exception
{
req.addAbandonListener( new SearchAbandonListener( ldapService, cursor ) );
setTimeLimitsOnCursor( req, session, cursor );
- LOG.debug( "using {} for size limit", sizeLimit );
+ LOG.debug( "using <{},{}> for size limit", requestLimit, serverLimit );
int cookieValue = 0;
+ int sizeLimit = min( requestLimit, serverLimit );
int count = 0;
@@ -409,17 +443,13 @@
}
else
{
- int serverLimit = session.getCoreSession().getDirectoryService().getMaxSizeLimit();
-
- if ( serverLimit == 0 )
- {
- serverLimit = Integer.MAX_VALUE;
- }
-
// DO NOT WRITE THE RESPONSE - JUST RETURN IT
- if ( count > serverLimit )
+ if ( ( count >= sizeLimit ) && ( cursor.next() ) )
{
- // Special case if the user has requested more elements than the limit
+ // Move backward on the cursor to restore the previous position, as we moved forward
+ // to check if there is one more entry available
+ cursor.previous();
+ // Special case if the user has requested more elements than the request size limit
ldapResult.setResultCode( ResultCodeEnum.SIZE_LIMIT_EXCEEDED );
}
@@ -428,154 +458,228 @@
}
}
+
/**
- * Conducts a simple search across the result set returning each entry
- * back except for the search response done. This is calculated but not
- * returned so the persistent search mechanism can leverage this method
- * along with standard search.
- *
- * @param session the LDAP session object for this request
- * @param req the search request
- * @return the result done
- * @throws Exception if there are failures while processing the request
+ * Manage the abandoned Paged Search (when paged size = 0). We have to
+ * remove the cookie and its associated cursor from the session.
*/
- private SearchResponseDone doSimpleSearch( LdapSession session, SearchRequest req )
+ private SearchResponseDone abandonPagedSearch( LdapSession session, SearchRequest req )
throws Exception
{
+ PagedResultsControl pagedResultsControl = null;
+ PagedSearchControl pagedSearchControl =
+ ( PagedSearchControl )req.getControls().get( PagedSearchControl.CONTROL_OID );
+ byte [] cookie= pagedSearchControl.getCookie();
+
+ if ( !StringTools.isEmpty( cookie ) )
+ {
+ // If the cookie is not null, we have to destroy the associated
+ // cursor stored into the session (if any)
+ int cookieValue = pagedSearchControl.getCookieValue();
+ PagedSearchCookie psCookie =
+ (PagedSearchCookie)session.getIoSession().removeAttribute( cookieValue );
+ pagedResultsControl = new PagedResultsControl( 0, psCookie.getCookie(), true );
+
+ // Close the cursor
+ EntryFilteringCursor cursor = psCookie.getCursor();
+
+ if ( cursor != null )
+ {
+ cursor.close();
+ }
+ }
+ else
+ {
+ pagedResultsControl = new PagedResultsControl( 0, true );
+ }
+
+ // and return
+ // DO NOT WRITE THE RESPONSE - JUST RETURN IT
LdapResult ldapResult = req.getResultResponse().getLdapResult();
+ ldapResult.setResultCode( ResultCodeEnum.SUCCESS );
+ req.getResultResponse().add( pagedResultsControl );
+ return ( SearchResponseDone ) req.getResultResponse();
+ }
+
+
+ /**
+ * Handle a Paged Search.
+ */
+ private SearchResponseDone doPagedSearch( LdapSession session, SearchRequest req, PagedSearchControl control )
+ {
+ return null;
+ /*
+ PagedSearchControl pagedSearchControl = ( PagedSearchControl )control;
PagedResultsControl pagedResultsControl = null;
+ int serverLimit = ldapService.getMaxSizeLimit() == 0 ?
+ Integer.MAX_VALUE : ldapService.getMaxSizeLimit();
+ int requestLimit = req.getSizeLimit() == 0 ?
+ Integer.MAX_VALUE : req.getSizeLimit();
+ int pagedLimit = pagedSearchControl.getSize();
EntryFilteringCursor cursor = null;
- int sizeLimit = getSearchSizeLimits( req, session );
- boolean isPaged = false;
PagedSearchCookie cookieInstance = null;
- // Check that the PagedSearchControl is present or not.
- // Check if we are using the Paged Search Control
- Object control = req.getControls().get( PagedSearchControl.CONTROL_OID );
- PagedSearchControl pagedSearchControl = null;
-
- if ( control != null )
- {
- pagedSearchControl = ( PagedSearchControl )control;
- }
+ // We have the following cases :
+ // 1) The SIZE is 0 and the cookie is the same than the previous one : this
+ // is a abandon request for this paged search.
+ // 2) The cookie is empty : this is a new request. If the requested
+ // size is above the serverLimit and the request limit, this is a normal
+ // search
+ // 3) The cookie is not empty and the request is the same, we return
+ // the next SIZE elements
+ // 4) The cookie is not empty, but the request is not the same : this is
+ // a new request (we have to discard the cookie and do a new search from
+ // the beginning)
+ // 5) The SIZE is above the size-limit : the request is treated as if it
+ // was a simple search
+
+ // Case 1
+ if ( pagedLimit == 0 )
+ {
+ // An abandoned paged search
+ return abandonPagedSearch( session, req );
+ }
+
+ // Now, depending on the cookie, we will deal with case 2, 3, 4 and 5
+ pagedLimit = pagedSearchControl.getSize();
+ byte [] cookie= pagedSearchControl.getCookie();
- if ( pagedSearchControl != null )
+ if ( StringTools.isEmpty( cookie ) )
{
- // We have the following cases :
- // 1) The SIZE is above the size-limit : the request is treated as if it
- // was a simple search
- // 2) The cookie is empty : this is a new request
- // 3) The cookie is not empty, but the request is not the same : this is
- // a new request (we have to discard the cookie and do a new search from
- // the beginning)
- // 4) The cookie is not empty and the request is the same, we return
- // the next SIZE elements
- // 5) The SIZE is 0 and the cookie is the same than the previous one : this
- // is a abandon request for this paged search.
- int size = pagedSearchControl.getSize();
- byte [] cookie= pagedSearchControl.getCookie();
-
- // Case 5
- if ( size == 0 )
- {
- // Remove the cookie from the session, if it's not null
- if ( !StringTools.isEmpty( cookie ) )
- {
- int cookieValue = pagedSearchControl.getCookieValue();
- PagedSearchCookie psCookie =
- (PagedSearchCookie)session.getIoSession().removeAttribute( cookieValue );
- pagedResultsControl = new PagedResultsControl( 0, psCookie.getCookie(), true );
-
- // Close the cursor
- cursor = psCookie.getCursor();
-
- if ( cursor != null )
+ // This is a new search.
+ if ( ( pagedLimit > serverLimit ) && ( pagedLimit > requestLimit ) )
+ {
+ // Normal search : create the cursor, and set pagedControl to false
+ try
+ {
+ readResults( session, req, ldapResult, cursor, min( serverLimit, requestLimit ), true, cookieInstance, pagedResultsControl );
+ }
+ finally
+ {
+ try
{
cursor.close();
}
- }
- else
- {
- pagedResultsControl = new PagedResultsControl( 0, true );
+ catch ( NamingException e )
+ {
+ LOG.error( "failed on list.close()", e );
+ }
}
- // and return
- // DO NOT WRITE THE RESPONSE - JUST RETURN IT
- ldapResult.setResultCode( ResultCodeEnum.SUCCESS );
- req.getResultResponse().add( pagedResultsControl );
return ( SearchResponseDone ) req.getResultResponse();
}
+ // Case 2 : create the cookie
+ cookieInstance = new PagedSearchCookie( req );
+ cookie = cookieInstance.getCookie();
+ int cookieValue = cookieInstance.getCookieValue();
+
+ session.getIoSession().setAttribute( cookieValue, cookieInstance );
+ pagedResultsControl = new PagedResultsControl( 0, cookie, true );
+ }
+ else
+ {
+ // Either case 3, 4 or 5
+ int cookieValue = pagedSearchControl.getCookieValue();
+ cookieInstance =
+ (PagedSearchCookie)session.getIoSession().getAttribute( cookieValue );
- if ( sizeLimit < size )
+ if ( cookieInstance.hasSameRequest( req, session ) )
{
- // Case 1
- cursor = session.getCoreSession().search( req );
+ // Case 3 : continue the search
+ cursor = cookieInstance.getCursor();
+
+ // get the cookie
+ cookie = cookieInstance.getCookie();
+ sizeLimit = size;
+ pagedResultsControl = new PagedResultsControl( 0, cookie, true );
}
else
{
- isPaged = true;
- sizeLimit = size;
+ // case 2 : create a new cursor
+ // We have to close the cursor
+ cursor = cookieInstance.getCursor();
- // Now, depending on the cookie, we will deal with case 2, 3 and 4
- if ( StringTools.isEmpty( cookie ) )
+ if ( cursor != null )
{
- // Case 2 : create the cookie
- cookieInstance = new PagedSearchCookie( req );
- cookie = cookieInstance.getCookie();
- int cookieValue = cookieInstance.getCookieValue();
-
- session.getIoSession().setAttribute( cookieValue, cookieInstance );
- pagedResultsControl = new PagedResultsControl( 0, cookie, true );
+ cursor.close();
}
- else
- {
- int cookieValue = pagedSearchControl.getCookieValue();
- cookieInstance =
- (PagedSearchCookie)session.getIoSession().getAttribute( cookieValue );
-
- if ( cookieInstance.hasSameRequest( req, session ) )
- {
- // Case 4 : continue the search
- cursor = cookieInstance.getCursor();
-
- // get the cookie
- cookie = cookieInstance.getCookie();
- isPaged = true;
- sizeLimit = size;
- pagedResultsControl = new PagedResultsControl( 0, cookie, true );
- }
- else
- {
- // case 3 : create a new cursor
- // We have to close the cursor
- cursor = cookieInstance.getCursor();
-
- if ( cursor != null )
- {
- cursor.close();
- }
-
- // Now create a new cookie and stores it into the session
- cookieInstance = new PagedSearchCookie( req );
- cookie = cookieInstance.getCookie();
- cookieValue = cookieInstance.getCookieValue();
+
+ // Now create a new cookie and stores it into the session
+ cookieInstance = new PagedSearchCookie( req );
+ cookie = cookieInstance.getCookie();
+ cookieValue = cookieInstance.getCookieValue();
- session.getIoSession().setAttribute( cookieValue, cookieInstance );
- pagedResultsControl = new PagedResultsControl( 0, cookie, true );
- }
- }
+ session.getIoSession().setAttribute( cookieValue, cookieInstance );
+ pagedResultsControl = new PagedResultsControl( 0, cookie, true );
}
}
+ */
+ }
+
+
+ /**
+ * Conducts a simple search across the result set returning each entry
+ * back except for the search response done. This is calculated but not
+ * returned so the persistent search mechanism can leverage this method
+ * along with standard search.<br>
+ * <br>
+ * The loop will stop when we have found all the entries, or if we
+ * have reached the limit, or if we have reached the paged limit. The
+ * following table describes the different possibilities (SL = server limit,
+ * RL = request limit, PL = paged limit)
+ *
+ * 1) SL=0, RL=0, PL=0 => no limit
+ * 2) SL=0, RL=0, PL=x => loop until we have sent X entries, or until we don't have
+ * any more entries to send
+ * 3) SL=0, RL=x, PL=0 => loop until we don't have anymore entries, or break and
+ * return an error if we reach the RL
+ * 4) SL=x, RL=0, PL=0 => loop until we don't have anymore entries, or break and
+ * return an error if we reach the SL
+ * 5) SL=0, RL=x, PL=y => if x > y, default to case (1), otherwise default to
+ * case (3)
+ * 6) SL=x, RL=0, PL=y => if x > y, default to case (1), otherwise default to
+ * case (4)
+ * 7) SL=x, RL=y, PL=0 => loop until we don't have anymore entries, or break and
+ * return an error if we reach the min(SL, RL)
+ * 8) SL=x, RL=y, PL=z => if z < min(x, y=, default to case 1, otherwise loop until
+ * we don't have anymore entries, or break and return an error if we reach the
+ * min(SL, RL)
+ *
+ *
+ * @param session the LDAP session object for this request
+ * @param req the search request
+ * @return the result done
+ * @throws Exception if there are failures while processing the request
+ */
+ private SearchResponseDone doSimpleSearch( LdapSession session, SearchRequest req )
+ throws Exception
+ {
+ LdapResult ldapResult = req.getResultResponse().getLdapResult();
+ PagedResultsControl pagedResultsControl = null;
- // Check that we have a cursor or not.
- if ( cursor == null )
+ // Get the size limits
+ // Don't bother setting size limits for administrators that don't ask for it
+ int serverLimit = getServerSizeLimit( session, req );
+
+ int requestLimit = req.getSizeLimit() == 0 ?
+ Integer.MAX_VALUE : req.getSizeLimit();
+
+ // Check if we are using the Paged Search Control
+ Object control = req.getControls().get( PagedSearchControl.CONTROL_OID );
+
+ if ( control != null )
{
+ // Let's deal with the pagedControl
+ return doPagedSearch( session, req, (PagedSearchControl)control );
+ }
+
+ // A normal search
+ // Check that we have a cursor or not.
// No cursor : do a search.
- cursor = session.getCoreSession().search( req );
+ EntryFilteringCursor cursor = session.getCoreSession().search( req );
- // Position the cursor at the beginning
- cursor.beforeFirst();
- }
+ // Position the cursor at the beginning
+ cursor.beforeFirst();
/*
* Iterate through all search results building and sending back responses
@@ -583,11 +687,11 @@
*/
try
{
- readResults( session, req, ldapResult, cursor, sizeLimit, isPaged, cookieInstance, pagedResultsControl );
+ readResults( session, req, ldapResult, cursor, requestLimit, serverLimit, false, null, pagedResultsControl );
}
finally
{
- if ( ( cursor != null ) && !isPaged )
+ if ( cursor != null )
{
try
{
Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchLimitsIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchLimitsIT.java?rev=726446&r1=726445&r2=726446&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchLimitsIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchLimitsIT.java Sun Dec 14 05:53:56 2008
@@ -34,7 +34,6 @@
import org.apache.directory.server.integ.SiRunner;
import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -277,20 +276,12 @@
* by request size limit value to cause a size limit exceeded exception on
* the client.
*/
- @Test
+ @Test (expected = SizeLimitExceededException.class)
public void testRequestConstrainedUnlimitByConfigurationSize() throws Exception
{
ldapService.setMaxSizeLimit( LdapService.NO_SIZE_LIMIT );
- try
- {
- getActorsWithLimit( "(objectClass=*)", LdapService.NO_TIME_LIMIT, 1 );
- assertTrue( true );
- }
- catch ( SizeLimitExceededException slee )
- {
- fail();
- }
+ getActorsWithLimit( "(objectClass=*)", LdapService.NO_TIME_LIMIT, 1 );
}
@@ -299,19 +290,12 @@
* which constrains size by request size limit value to cause a size limit
* exceeded exception on the client.
*/
- @Test
+ @Test ( expected = SizeLimitExceededException.class )
public void testRequestConstrainedLessThanConfigurationSize() throws Exception
{
ldapService.setMaxSizeLimit( 10000 );
- try
- {
- getActorsWithLimit( "(objectClass=*)", LdapService.NO_TIME_LIMIT, 1 );
- }
- catch ( SizeLimitExceededException slee )
- {
- fail();
- }
+ getActorsWithLimit( "(objectClass=*)", LdapService.NO_TIME_LIMIT, 1 );
}
@@ -333,7 +317,7 @@
* Sets up the server with shorter search size limit than the request's
* which constrains size by using server max limit value to cause a size
* limit exceeded exception on the client.
- * TODO : reestablish this test
+ */
@Test (expected = SizeLimitExceededException.class )
public void testNonAdminRequestConstrainedGreaterThanConfigurationSize() throws Exception
{
@@ -362,7 +346,7 @@
/**
* Sets up the server with limited search size with unlimited request
* size limit. Should not work for non administrative users.
- * TODO : reestablish this test
+ */
@Test ( expected = SizeLimitExceededException.class )
public void testNonAdminRequestUnlimitedConfigurationLimitedSize() throws Exception
{
@@ -382,7 +366,7 @@
* "sizeLimitExceeded (4)
* Indicates that the size limit specified by the client was
* exceeded before the operation could be completed."
- * TODO : reestablish this test
+ */
@Test ( expected = SizeLimitExceededException.class )
public void testRequestConstraintedLessThanExpectedSize() throws Exception
{