blob: f7472a0f531c57d40994b3d2504eabeef9862bfd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.core.partition.impl.btree;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
/**
* A prefetching NamingEnumeration over an underlying NamingEnumeration which
* determines if a element should be returned based on a Assertion.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public class IndexAssertionEnumeration implements NamingEnumeration<IndexRecord>
{
/** The prefetched candidate */
private final IndexRecord prefetched = new IndexRecord();
/** The returned candidate */
private final IndexRecord candidate = new IndexRecord();
/** The iteration cursor */
private final NamingEnumeration<IndexRecord> underlying;
/** LUT used to avoid returning duplicates */
private final Map<Object,Object> candidates;
/** */
private final IndexAssertion assertion;
/** */
private final boolean checkDups;
/** */
private boolean hasMore = true;
// ------------------------------------------------------------------------
// C O N S T R U C T O R S
// ------------------------------------------------------------------------
public IndexAssertionEnumeration( NamingEnumeration<IndexRecord> underlying, IndexAssertion assertion )
throws NamingException
{
this.underlying = underlying;
candidates = null;
this.assertion = assertion;
checkDups = false;
prefetch();
}
public IndexAssertionEnumeration( NamingEnumeration<IndexRecord> underlying, IndexAssertion assertion,
boolean enableDupCheck ) throws NamingException
{
this.underlying = underlying;
candidates = new HashMap<Object,Object>();
this.assertion = assertion;
checkDups = enableDupCheck;
prefetch();
}
// ------------------------------------------------------------------------
// Enumeration Method Implementations
// ------------------------------------------------------------------------
/**
* @see java.util.Enumeration#nextElement()
*/
public IndexRecord nextElement()
{
try
{
return next();
}
catch ( NamingException e )
{
throw new NoSuchElementException();
}
}
/**
* @see java.util.Enumeration#hasMoreElements()
*/
public boolean hasMoreElements()
{
return hasMore;
}
// ------------------------------------------------------------------------
// NamingEnumeration Method Implementations
// ------------------------------------------------------------------------
/**
* @see javax.naming.NamingEnumeration#next()
*/
public IndexRecord next() throws NamingException
{
candidate.copy( prefetched );
prefetch();
return candidate;
}
/**
* @see javax.naming.NamingEnumeration#hasMore()
*/
public boolean hasMore()
{
return hasMore;
}
/**
* @see javax.naming.NamingEnumeration#close()
*/
public void close() throws NamingException
{
hasMore = false;
underlying.close();
}
// ------------------------------------------------------------------------
// Private and Protected Methods
// ------------------------------------------------------------------------
private void prefetch() throws NamingException
{
IndexRecord rec = null;
/*
* Scan underlying Cursor until we arrive at the next valid candidate
* if the cursor is exhuasted we clean up after completing the loop
*/
while ( underlying.hasMore() )
{
rec = underlying.next();
// If value is valid then we set it as the next candidate to return
if ( assertion.assertCandidate( rec ) )
{
if ( checkDups )
{
boolean dup = candidates.containsKey( rec.getEntryId() );
if ( dup )
{
/*
* Dup checking is on and candidate is a duplicate that
* has already been seen so we need to skip it.
*/
continue;
}
else
{
/*
* Dup checking is on and the candidate is not in the
* dup LUT so we need to set it as the next to return
* and add it to the LUT in case we encounter it another
* time.
*/
prefetched.copy( rec );
candidates.put( rec.getEntryId(), rec.getEntryId() );
return;
}
}
prefetched.copy( rec );
return;
}
}
// At this pt the underlying Cursor has been exhausted so we close up
close();
}
}