blob: 465ae5927f69d853bec608955f7b1bc66b6739f0 [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 org.apache.directory.server.core.entry.DefaultServerEntry;
import org.apache.directory.server.core.entry.ServerEntry;
import org.apache.directory.server.core.entry.ServerSearchResult;
import org.apache.directory.server.core.enumeration.SearchResultEnumeration;
import org.apache.directory.server.core.interceptor.context.AddOperationContext;
import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
import org.apache.directory.server.core.interceptor.context.ListOperationContext;
import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
import org.apache.directory.server.core.partition.Oid;
import org.apache.directory.server.core.partition.Partition;
import org.apache.directory.server.core.partition.impl.btree.gui.PartitionViewer;
import org.apache.directory.server.schema.registries.Registries;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.exception.LdapContextNotEmptyException;
import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
import org.apache.directory.shared.ldap.name.LdapDN;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* An abstract {@link Partition} that uses general BTree operations.
*
* @org.apache.xbean.XBean
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public abstract class BTreePartition implements Partition
{
protected static final Set<String> SYS_INDEX_OIDS;
static
{
Set<String> set = new HashSet<String>();
set.add( Oid.ALIAS );
set.add( Oid.EXISTANCE );
set.add( Oid.HIERARCHY );
set.add( Oid.NDN );
set.add( Oid.ONEALIAS );
set.add( Oid.SUBALIAS );
set.add( Oid.UPDN );
SYS_INDEX_OIDS = Collections.unmodifiableSet( set );
}
/** the search engine used to search the database */
protected SearchEngine searchEngine;
protected Optimizer optimizer;
protected Registries registries;
protected String id;
protected int cacheSize = -1;
protected LdapDN suffixDn;
protected String suffix;
/** The rootDSE context */
protected ServerEntry contextEntry;
// ------------------------------------------------------------------------
// C O N S T R U C T O R S
// ------------------------------------------------------------------------
/**
* Creates a B-tree based context partition.
*/
protected BTreePartition()
{
}
// ------------------------------------------------------------------------
// C O N F I G U R A T I O N M E T H O D S
// ------------------------------------------------------------------------
/**
* Used to specify the entry cache size for a Partition. Various Partition
* implementations may interpret this value in different ways: i.e. total cache
* size limit verses the number of entries to cache.
*
* @param cacheSize the maximum size of the cache in the number of entries
*/
public void setCacheSize( int cacheSize )
{
this.cacheSize = cacheSize;
}
/**
* Gets the entry cache size for this BTreePartition.
*
* @return the maximum size of the cache as the number of entries maximum before paging out
*/
public int getCacheSize()
{
return cacheSize;
}
/**
* Returns root entry for this BTreePartition.
*
* @return the root suffix entry for this BTreePartition
*/
public ServerEntry getContextEntry()
{
if ( contextEntry != null )
{
return ( ServerEntry ) contextEntry.clone();
}
else
{
return null;
}
}
/**
* Sets root entry for this BTreePartition.
*
* @param rootEntry the root suffix entry of this BTreePartition
*/
public void setContextEntry( ServerEntry rootEntry )
{
this.contextEntry = ( ServerEntry ) rootEntry.clone();
}
/**
* Sets root entry for this BTreePartition.
*
* @param rootEntry the root suffix entry of this BTreePartition
*/
public void setContextEntry( String rootEntry )
{
System.out.println( rootEntry );
}
/**
* Gets the unique identifier for this partition.
*
* @return the unique identifier for this partition
*/
public String getId()
{
return id;
}
/**
* Sets the unique identifier for this partition.
*
* @param id the unique identifier for this partition
*/
public void setId( String id )
{
this.id = id;
}
// -----------------------------------------------------------------------
// E N D C O N F I G U R A T I O N M E T H O D S
// -----------------------------------------------------------------------
/**
* Allows for schema entity registries to be swapped out during runtime. This is
* primarily here to facilitate the swap out of a temporary bootstrap registry.
* Registry changes require swapping out the search engine used by a partition
* since the registries are used by elements in the search engine.
*
* @param registries the schema entity registries
*/
public abstract void setRegistries( Registries registries );
// ------------------------------------------------------------------------
// Public Accessors - not declared in any interfaces just for this class
// ------------------------------------------------------------------------
/**
* Gets the DefaultSearchEngine used by this ContextPartition to search the
* Database.
*
* @return the search engine
*/
public SearchEngine getSearchEngine()
{
return searchEngine;
}
// ------------------------------------------------------------------------
// Partition Interface Method Implementations
// ------------------------------------------------------------------------
public void delete( DeleteOperationContext opContext ) throws NamingException
{
LdapDN dn = opContext.getDn();
Long id = getEntryId( dn.getNormName() );
// don't continue if id is null
if ( id == null )
{
throw new LdapNameNotFoundException( "Could not find entry at '" + dn + "' to delete it!" );
}
if ( getChildCount( id ) > 0 )
{
LdapContextNotEmptyException cnee = new LdapContextNotEmptyException( "[66] Cannot delete entry " + dn
+ " it has children!" );
cnee.setRemainingName( dn );
throw cnee;
}
delete( id );
}
public abstract void add( AddOperationContext opContext ) throws NamingException;
public abstract void modify( ModifyOperationContext opContext ) throws NamingException;
private static final String[] ENTRY_DELETED_ATTRS = new String[] { "entrydeleted" };
public NamingEnumeration<ServerSearchResult> list( ListOperationContext opContext ) throws NamingException
{
SearchResultEnumeration list;
list = new BTreeSearchResultEnumeration( ENTRY_DELETED_ATTRS, list( getEntryId( opContext.getDn().getNormName() ) ),
this, registries );
return list;
}
public NamingEnumeration<ServerSearchResult> search( SearchOperationContext opContext )
throws NamingException
{
SearchControls searchCtls = opContext.getSearchControls();
String[] attrIds = searchCtls.getReturningAttributes();
NamingEnumeration<IndexRecord> underlying;
underlying = searchEngine.search(
opContext.getDn(),
opContext.getAliasDerefMode(),
opContext.getFilter(),
searchCtls );
return new BTreeSearchResultEnumeration( attrIds, underlying, this, registries );
}
public ServerEntry lookup( LookupOperationContext opContext ) throws NamingException
{
ServerEntry entry = lookup( getEntryId( opContext.getDn().getNormName() ) );
if ( ( opContext.getAttrsId() == null ) || ( opContext.getAttrsId().size() == 0 ) )
{
return entry;
}
ServerEntry retval = new DefaultServerEntry( opContext.getRegistries(), opContext.getDn() );
for ( String attrId:opContext.getAttrsId() )
{
EntryAttribute attr = entry.get( attrId );
if ( attr != null )
{
retval.put( attr );
}
}
return retval;
}
public boolean hasEntry( EntryOperationContext opContext ) throws NamingException
{
return null != getEntryId( opContext.getDn().getNormName() );
}
public abstract void rename( RenameOperationContext opContext ) throws NamingException;
public abstract void move( MoveOperationContext opContext ) throws NamingException;
public abstract void moveAndRename( MoveAndRenameOperationContext opContext )
throws NamingException;
public abstract void sync() throws NamingException;
public abstract void destroy();
public abstract boolean isInitialized();
public void inspect() throws Exception
{
PartitionViewer viewer = new PartitionViewer( this, registries );
viewer.execute();
}
////////////////////
// public abstract methods
// ------------------------------------------------------------------------
// Index Operations
// ------------------------------------------------------------------------
public abstract void addIndexOn( Index index ) throws NamingException;
public abstract boolean hasUserIndexOn( String attribute ) throws NamingException;
public abstract boolean hasSystemIndexOn( String attribute ) throws NamingException;
public abstract Index getExistanceIndex();
/**
* Gets the Index mapping the BigInteger primary keys of parents to the
* BigInteger primary keys of their children.
*
* @return the hierarchy Index
*/
public abstract Index getHierarchyIndex();
/**
* Gets the Index mapping user provided distinguished names of entries as
* Strings to the BigInteger primary keys of entries.
*
* @return the user provided distinguished name Index
*/
public abstract Index getUpdnIndex();
/**
* Gets the Index mapping the normalized distinguished names of entries as
* Strings to the BigInteger primary keys of entries.
*
* @return the normalized distinguished name Index
*/
public abstract Index getNdnIndex();
/**
* Gets the alias index mapping parent entries with scope expanding aliases
* children one level below them; this system index is used to dereference
* aliases on one/single level scoped searches.
*
* @return the one alias index
*/
public abstract Index getOneAliasIndex();
/**
* Gets the alias index mapping relative entries with scope expanding
* alias descendents; this system index is used to dereference aliases on
* subtree scoped searches.
*
* @return the sub alias index
*/
public abstract Index getSubAliasIndex();
/**
* Gets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
* be the aliasedObjectName and for X.500 would be aliasedEntryName.
*
* @return the index on the ALIAS_ATTRIBUTE
*/
public abstract Index getAliasIndex();
/**
* Sets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
* be the aliasedObjectName and for X.500 would be aliasedEntryName.
*
* @param index the index on the ALIAS_ATTRIBUTE
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setAliasIndexOn( Index index ) throws NamingException;
/**
* Sets the attribute existance Index.
*
* @param index the attribute existance Index
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setExistanceIndexOn( Index index ) throws NamingException;
/**
* Sets the hierarchy Index.
*
* @param index the hierarchy Index
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setHierarchyIndexOn( Index index ) throws NamingException;
/**
* Sets the user provided distinguished name Index.
*
* @param index the updn Index
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setUpdnIndexOn( Index index ) throws NamingException;
/**
* Sets the normalized distinguished name Index.
*
* @param index the ndn Index
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setNdnIndexOn( Index index ) throws NamingException;
/**
* Sets the alias index mapping parent entries with scope expanding aliases
* children one level below them; this system index is used to dereference
* aliases on one/single level scoped searches.
*
* @param index a one level alias index
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setOneAliasIndexOn( Index index ) throws NamingException;
/**
* Sets the alias index mapping relative entries with scope expanding
* alias descendents; this system index is used to dereference aliases on
* subtree scoped searches.
*
* @param index a subtree alias index
* @throws NamingException if there is a problem setting up the index
*/
public abstract void setSubAliasIndexOn( Index index ) throws NamingException;
public abstract Index getUserIndex( String attribute ) throws IndexNotFoundException;
public abstract Index getSystemIndex( String attribute ) throws IndexNotFoundException;
public abstract Long getEntryId( String dn ) throws NamingException;
public abstract String getEntryDn( Long id ) throws NamingException;
public abstract Long getParentId( String dn ) throws NamingException;
public abstract Long getParentId( Long childId ) throws NamingException;
/**
* Gets the user provided distinguished name.
*
* @param id the entry id
* @return the user provided distinguished name
* @throws NamingException if the updn index cannot be accessed
*/
public abstract String getEntryUpdn( Long id ) throws NamingException;
/**
* Gets the user provided distinguished name.
*
* @param dn the normalized distinguished name
* @return the user provided distinguished name
* @throws NamingException if the updn and ndn indices cannot be accessed
*/
public abstract String getEntryUpdn( String dn ) throws NamingException;
public abstract ServerEntry lookup( Long id ) throws NamingException;
public abstract void delete( Long id ) throws NamingException;
public abstract NamingEnumeration<IndexRecord> list( Long id ) throws NamingException;
public abstract int getChildCount( Long id ) throws NamingException;
public abstract ServerEntry getSuffixEntry() throws NamingException;
public abstract void setProperty( String key, String value ) throws NamingException;
public abstract String getProperty( String key ) throws NamingException;
public abstract Iterator<String> getUserIndices();
public abstract Iterator<String> getSystemIndices();
public abstract ServerEntry getIndices( Long id ) throws NamingException;
/**
* Gets the count of the total number of entries in the database.
*
* TODO shouldn't this be a BigInteger instead of an int?
*
* @return the number of entries in the database
* @throws NamingException if there is a failure to read the count
*/
public abstract int count() throws NamingException;
}