| | |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.core.ModifyDNOperation; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.controls.PagedResultsControl; |
| | | import org.opends.server.controls.ServerSideSortRequestControl; |
| | | import org.opends.server.controls.ServerSideSortResponseControl; |
| | | import org.opends.server.controls.SubtreeDeleteControl; |
| | | import org.opends.server.controls.VLVRequestControl; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.util.StaticUtils; |
| | |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import static org.opends.server.loggers.ErrorLogger.logError; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import org.opends.server.admin.std.server.LocalDBBackendCfg; |
| | | import org.opends.server.admin.std.server.LocalDBIndexCfg; |
| | | import org.opends.server.admin.std.server.LocalDBVLVIndexCfg; |
| | |
| | | * the guts of the backend API methods for LDAP operations. |
| | | */ |
| | | public class EntryContainer |
| | | implements ConfigurationChangeListener<LocalDBBackendCfg> |
| | | implements ConfigurationChangeListener<LocalDBBackendCfg> |
| | | { |
| | | /** |
| | | * The tracer object for the debug logger. |
| | |
| | | /** |
| | | * The backend to which this entry entryContainer belongs. |
| | | */ |
| | | private Backend backend; |
| | | private final Backend backend; |
| | | |
| | | /** |
| | | * The root container in which this entryContainer belongs. |
| | | */ |
| | | private RootContainer rootContainer; |
| | | private final RootContainer rootContainer; |
| | | |
| | | /** |
| | | * The baseDN this entry container is responsible for. |
| | | */ |
| | | private DN baseDN; |
| | | private final DN baseDN; |
| | | |
| | | /** |
| | | * The backend configuration. |
| | |
| | | /** |
| | | * The JE database environment. |
| | | */ |
| | | private Environment env; |
| | | private final Environment env; |
| | | |
| | | /** |
| | | * The DN database maps a normalized DN string to an entry ID (8 bytes). |
| | |
| | | /** |
| | | * The set of attribute indexes. |
| | | */ |
| | | private HashMap<AttributeType, AttributeIndex> attrIndexMap; |
| | | private final HashMap<AttributeType, AttributeIndex> attrIndexMap; |
| | | |
| | | /** |
| | | * The set of VLV indexes. |
| | | */ |
| | | private HashMap<String, VLVIndex> vlvIndexMap; |
| | | private final HashMap<String, VLVIndex> vlvIndexMap; |
| | | |
| | | private String databasePrefix; |
| | | /** |
| | |
| | | * indexes used within this entry container. |
| | | */ |
| | | public class AttributeJEIndexCfgManager implements |
| | | ConfigurationAddListener<LocalDBIndexCfg>, |
| | | ConfigurationDeleteListener<LocalDBIndexCfg> |
| | | ConfigurationAddListener<LocalDBIndexCfg>, |
| | | ConfigurationDeleteListener<LocalDBIndexCfg> |
| | | { |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationAddAcceptable( |
| | | LocalDBIndexCfg cfg, |
| | | List<Message> unacceptableReasons) |
| | | LocalDBIndexCfg cfg, |
| | | List<Message> unacceptableReasons) |
| | | { |
| | | // TODO: validate more before returning true? |
| | | return true; |
| | |
| | | try |
| | | { |
| | | AttributeIndex index = |
| | | new AttributeIndex(cfg, state, env, EntryContainer.this); |
| | | new AttributeIndex(cfg, state, env, EntryContainer.this); |
| | | index.open(); |
| | | if(!index.isTrusted()) |
| | | { |
| | |
| | | { |
| | | messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(e))); |
| | | ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(), |
| | | adminActionRequired, |
| | | messages); |
| | | adminActionRequired, |
| | | messages); |
| | | return ccr; |
| | | } |
| | | |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, |
| | | messages); |
| | | messages); |
| | | } |
| | | |
| | | /** |
| | |
| | | { |
| | | messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(de))); |
| | | ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(), |
| | | adminActionRequired, |
| | | messages); |
| | | adminActionRequired, |
| | | messages); |
| | | return ccr; |
| | | } |
| | | finally |
| | |
| | | } |
| | | |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, |
| | | messages); |
| | | messages); |
| | | } |
| | | } |
| | | |
| | |
| | | * used within this entry container. |
| | | */ |
| | | public class VLVJEIndexCfgManager implements |
| | | ConfigurationAddListener<LocalDBVLVIndexCfg>, |
| | | ConfigurationDeleteListener<LocalDBVLVIndexCfg> |
| | | ConfigurationAddListener<LocalDBVLVIndexCfg>, |
| | | ConfigurationDeleteListener<LocalDBVLVIndexCfg> |
| | | { |
| | | /** |
| | | * {@inheritDoc} |
| | |
| | | String[] sortAttrs = cfg.getSortOrder().split(" "); |
| | | SortKey[] sortKeys = new SortKey[sortAttrs.length]; |
| | | OrderingMatchingRule[] orderingRules = |
| | | new OrderingMatchingRule[sortAttrs.length]; |
| | | new OrderingMatchingRule[sortAttrs.length]; |
| | | boolean[] ascending = new boolean[sortAttrs.length]; |
| | | for(int i = 0; i < sortAttrs.length; i++) |
| | | { |
| | |
| | | catch(Exception e) |
| | | { |
| | | Message msg = |
| | | ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get( |
| | | String.valueOf(sortKeys[i]), cfg.getName()); |
| | | ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get( |
| | | String.valueOf(sortKeys[i]), cfg.getName()); |
| | | unacceptableReasons.add(msg); |
| | | return false; |
| | | } |
| | | |
| | | AttributeType attrType = |
| | | DirectoryServer.getAttributeType(sortAttrs[i].toLowerCase()); |
| | | DirectoryServer.getAttributeType(sortAttrs[i].toLowerCase()); |
| | | if(attrType == null) |
| | | { |
| | | Message msg = ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get( |
| | |
| | | { |
| | | messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(e))); |
| | | ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(), |
| | | adminActionRequired, |
| | | messages); |
| | | adminActionRequired, |
| | | messages); |
| | | return ccr; |
| | | } |
| | | |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, |
| | | messages); |
| | | messages); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationDeleteAcceptable( |
| | | LocalDBVLVIndexCfg cfg, |
| | | List<Message> unacceptableReasons) |
| | | LocalDBVLVIndexCfg cfg, |
| | | List<Message> unacceptableReasons) |
| | | { |
| | | // TODO: validate more before returning true? |
| | | return true; |
| | |
| | | try |
| | | { |
| | | VLVIndex vlvIndex = |
| | | vlvIndexMap.get(cfg.getName().toLowerCase()); |
| | | vlvIndexMap.get(cfg.getName().toLowerCase()); |
| | | vlvIndex.close(); |
| | | deleteDatabase(vlvIndex); |
| | | vlvIndexMap.remove(cfg.getName()); |
| | |
| | | { |
| | | messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(de))); |
| | | ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(), |
| | | adminActionRequired, |
| | | messages); |
| | | adminActionRequired, |
| | | messages); |
| | | return ccr; |
| | | } |
| | | finally |
| | |
| | | } |
| | | |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, |
| | | messages); |
| | | messages); |
| | | } |
| | | |
| | | } |
| | |
| | | * @throws ConfigException if a configuration related error occurs. |
| | | */ |
| | | public EntryContainer(DN baseDN, String databasePrefix, Backend backend, |
| | | LocalDBBackendCfg config, Environment env, |
| | | RootContainer rootContainer) |
| | | throws ConfigException |
| | | LocalDBBackendCfg config, Environment env, |
| | | RootContainer rootContainer) |
| | | throws ConfigException |
| | | { |
| | | this.backend = backend; |
| | | this.baseDN = baseDN; |
| | |
| | | config.addLocalDBChangeListener(this); |
| | | |
| | | attributeJEIndexCfgManager = |
| | | new AttributeJEIndexCfgManager(); |
| | | new AttributeJEIndexCfgManager(); |
| | | config.addLocalDBIndexAddListener(attributeJEIndexCfgManager); |
| | | config.addLocalDBIndexDeleteListener(attributeJEIndexCfgManager); |
| | | |
| | | vlvJEIndexCfgManager = |
| | | new VLVJEIndexCfgManager(); |
| | | new VLVJEIndexCfgManager(); |
| | | config.addLocalDBVLVIndexAddListener(vlvJEIndexCfgManager); |
| | | config.addLocalDBVLVIndexDeleteListener(vlvJEIndexCfgManager); |
| | | } |
| | |
| | | * @throws ConfigException if a configuration related error occurs. |
| | | */ |
| | | public void open() |
| | | throws DatabaseException, ConfigException |
| | | throws DatabaseException, ConfigException |
| | | { |
| | | try |
| | | { |
| | | DataConfig entryDataConfig = |
| | | new DataConfig(config.isEntriesCompressed(), |
| | | config.isCompactEncoding(), |
| | | rootContainer.getCompressedSchema()); |
| | | new DataConfig(config.isEntriesCompressed(), |
| | | config.isCompactEncoding(), |
| | | rootContainer.getCompressedSchema()); |
| | | |
| | | id2entry = new ID2Entry(databasePrefix + "_" + ID2ENTRY_DATABASE_NAME, |
| | | entryDataConfig, env, this); |
| | | entryDataConfig, env, this); |
| | | id2entry.open(); |
| | | |
| | | dn2id = new DN2ID(databasePrefix + "_" + DN2ID_DATABASE_NAME, env, this); |
| | |
| | | state.open(); |
| | | |
| | | id2children = new Index(databasePrefix + "_" + ID2CHILDREN_DATABASE_NAME, |
| | | new ID2CIndexer(), state, |
| | | config.getIndexEntryLimit(), 0, true, |
| | | env,this); |
| | | new ID2CIndexer(), state, |
| | | config.getIndexEntryLimit(), 0, true, |
| | | env,this); |
| | | id2children.open(); |
| | | |
| | | if(!id2children.isTrusted()) |
| | |
| | | } |
| | | |
| | | id2subtree = new Index(databasePrefix + "_" + ID2SUBTREE_DATABASE_NAME, |
| | | new ID2SIndexer(), state, |
| | | config.getIndexEntryLimit(), 0, true, |
| | | env, this); |
| | | new ID2SIndexer(), state, |
| | | config.getIndexEntryLimit(), 0, true, |
| | | env, this); |
| | | id2subtree.open(); |
| | | |
| | | if(!id2subtree.isTrusted()) |
| | |
| | | } |
| | | |
| | | dn2uri = new DN2URI(databasePrefix + "_" + REFERRAL_DATABASE_NAME, |
| | | env, this); |
| | | env, this); |
| | | dn2uri.open(); |
| | | |
| | | for (String idx : config.listLocalDBIndexes()) |
| | |
| | | LocalDBIndexCfg indexCfg = config.getLocalDBIndex(idx); |
| | | |
| | | AttributeIndex index = |
| | | new AttributeIndex(indexCfg, state, env, this); |
| | | new AttributeIndex(indexCfg, state, env, this); |
| | | index.open(); |
| | | if(!index.isTrusted()) |
| | | { |
| | |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public void close() |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | // Close core indexes. |
| | | dn2id.close(); |
| | |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public long getNumSubordinates(DN entryDN, boolean subtree) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | EntryID entryID = dn2id.get(null, entryDN, LockMode.DEFAULT); |
| | | if (entryID != null) |
| | | { |
| | | DatabaseEntry key = |
| | | new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue())); |
| | | new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue())); |
| | | EntryIDSet entryIDSet; |
| | | if(!subtree) |
| | | { |
| | |
| | | * @throws CanceledOperationException if this operation should be cancelled. |
| | | */ |
| | | public void search(SearchOperation searchOperation) |
| | | throws DirectoryException, DatabaseException, CanceledOperationException |
| | | throws DirectoryException, DatabaseException, CanceledOperationException |
| | | { |
| | | DN baseDN = searchOperation.getBaseDN(); |
| | | SearchScope searchScope = searchOperation.getScope(); |
| | | |
| | | List<Control> controls = searchOperation.getRequestControls(); |
| | | PagedResultsControl pageRequest = null; |
| | | ServerSideSortRequestControl sortRequest = null; |
| | | VLVRequestControl vlvRequest = null; |
| | | if (controls != null) |
| | | PagedResultsControl pageRequest = searchOperation |
| | | .getRequestControl(PagedResultsControl.DECODER); |
| | | ServerSideSortRequestControl sortRequest = searchOperation |
| | | .getRequestControl(ServerSideSortRequestControl.DECODER); |
| | | VLVRequestControl vlvRequest = searchOperation |
| | | .getRequestControl(VLVRequestControl.DECODER); |
| | | |
| | | if (vlvRequest != null && pageRequest != null) |
| | | { |
| | | for (Control control : controls) |
| | | { |
| | | if (control.getOID().equals(OID_PAGED_RESULTS_CONTROL)) |
| | | { |
| | | // Ignore all but the first paged results control. |
| | | if (pageRequest == null) |
| | | { |
| | | try |
| | | { |
| | | pageRequest = new PagedResultsControl(control.isCritical(), |
| | | control.getValue()); |
| | | } |
| | | catch (LDAPException e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | throw new DirectoryException(ResultCode.PROTOCOL_ERROR, |
| | | e.getMessageObject(), e); |
| | | } |
| | | |
| | | if (vlvRequest != null) |
| | | { |
| | | Message message = |
| | | ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get(); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | message); |
| | | } |
| | | } |
| | | } |
| | | else if (control.getOID().equals(OID_SERVER_SIDE_SORT_REQUEST_CONTROL)) |
| | | { |
| | | // Ignore all but the first sort request control. |
| | | if (sortRequest == null) |
| | | { |
| | | try |
| | | { |
| | | sortRequest = ServerSideSortRequestControl.decodeControl(control); |
| | | } |
| | | catch (LDAPException e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | throw new DirectoryException(ResultCode.PROTOCOL_ERROR, |
| | | e.getMessageObject(), e); |
| | | } |
| | | } |
| | | } |
| | | else if (control.getOID().equals(OID_VLV_REQUEST_CONTROL)) |
| | | { |
| | | // Ignore all but the first VLV request control. |
| | | if (vlvRequest == null) |
| | | { |
| | | try |
| | | { |
| | | vlvRequest = VLVRequestControl.decodeControl(control); |
| | | } |
| | | catch (LDAPException e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | throw new DirectoryException(ResultCode.PROTOCOL_ERROR, |
| | | e.getMessageObject(), e); |
| | | } |
| | | |
| | | if (pageRequest != null) |
| | | { |
| | | Message message = |
| | | ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get(); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | message); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | Message message = ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get(); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | // Handle client abandon of paged results. |
| | |
| | | if (pageRequest.getSize() == 0) |
| | | { |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, |
| | | new ASN1OctetString()); |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, null); |
| | | searchOperation.getResponseControls().add(control); |
| | | return; |
| | | } |
| | |
| | | { |
| | | // Indicate no more pages. |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, |
| | | new ASN1OctetString()); |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, null); |
| | | searchOperation.getResponseControls().add(control); |
| | | } |
| | | |
| | |
| | | try |
| | | { |
| | | entryIDList = |
| | | vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest, |
| | | debugBuffer); |
| | | vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest, |
| | | debugBuffer); |
| | | if(entryIDList != null) |
| | | { |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, |
| | | null)); |
| | | null)); |
| | | candidatesAreInScope = true; |
| | | break; |
| | | } |
| | |
| | | { |
| | | // Create an index filter to get the search result candidate entries. |
| | | IndexFilter indexFilter = |
| | | new IndexFilter(this, searchOperation, debugBuffer); |
| | | new IndexFilter(this, searchOperation, debugBuffer); |
| | | |
| | | // Evaluate the filter against the attribute indexes. |
| | | entryIDList = indexFilter.evaluate(); |
| | |
| | | if (baseID == null) |
| | | { |
| | | Message message = |
| | | ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN.toString()); |
| | | ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN.toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | message, matchedDN, null); |
| | |
| | | try |
| | | { |
| | | entryIDList = EntryIDSetSorter.sort(this, entryIDList, |
| | | searchOperation, |
| | | sortRequest.getSortOrder(), |
| | | vlvRequest); |
| | | searchOperation, |
| | | sortRequest.getSortOrder(), |
| | | vlvRequest); |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, null)); |
| | | } |
| | |
| | | if (entryIDList.isDefined()) |
| | | { |
| | | searchIndexed(entryIDList, candidatesAreInScope, searchOperation, |
| | | pageRequest); |
| | | pageRequest); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | |
| | | ClientConnection clientConnection = |
| | | searchOperation.getClientConnection(); |
| | | searchOperation.getClientConnection(); |
| | | if(! clientConnection.hasPrivilege(Privilege.UNINDEXED_SEARCH, |
| | | searchOperation)) |
| | | searchOperation)) |
| | | { |
| | | Message message = |
| | | ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get(); |
| | | ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get(); |
| | | throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, |
| | | message); |
| | | message); |
| | | } |
| | | |
| | | if (sortRequest != null) |
| | |
| | | // FIXME -- Add support for sorting unindexed searches using indexes |
| | | // like DSEE currently does. |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl( |
| | | LDAPResultCode.UNWILLING_TO_PERFORM, null)); |
| | | new ServerSideSortResponseControl( |
| | | LDAPResultCode.UNWILLING_TO_PERFORM, null)); |
| | | |
| | | if (sortRequest.isCritical()) |
| | | { |
| | | Message message = ERR_JEB_SEARCH_CANNOT_SORT_UNINDEXED.get(); |
| | | throw new DirectoryException( |
| | | ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message); |
| | | ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message); |
| | | } |
| | | } |
| | | |
| | |
| | | * processed. |
| | | */ |
| | | private void searchNotIndexed(SearchOperation searchOperation, |
| | | PagedResultsControl pageRequest) |
| | | throws DirectoryException, CanceledOperationException |
| | | PagedResultsControl pageRequest) |
| | | throws DirectoryException, CanceledOperationException |
| | | { |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | DN baseDN = searchOperation.getBaseDN(); |
| | |
| | | // The base entry must already have been processed if this is |
| | | // a request for the next page in paged results. So we skip |
| | | // the base entry processing if the cookie is set. |
| | | if (pageRequest == null || pageRequest.getCookie().value().length == 0) |
| | | if (pageRequest == null || pageRequest.getCookie().length() == 0) |
| | | { |
| | | // Fetch the base entry. |
| | | Entry baseEntry = null; |
| | |
| | | // Indicate no more pages. |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, |
| | | new ASN1OctetString()); |
| | | null); |
| | | searchOperation.getResponseControls().add(control); |
| | | } |
| | | } |
| | |
| | | |
| | | // Set the starting value. |
| | | byte[] begin; |
| | | if (pageRequest != null && pageRequest.getCookie().value().length != 0) |
| | | if (pageRequest != null && pageRequest.getCookie().length() != 0) |
| | | { |
| | | // The cookie contains the DN of the next entry to be returned. |
| | | try |
| | |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | String str = StaticUtils.bytesToHex(pageRequest.getCookie().value()); |
| | | String str = pageRequest.getCookie().toHex(); |
| | | Message msg = ERR_JEB_INVALID_PAGED_RESULTS_COOKIE.get(str); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | msg, e); |
| | | msg, e); |
| | | } |
| | | } |
| | | else |
| | |
| | | |
| | | int lookthroughCount = 0; |
| | | int lookthroughLimit = |
| | | searchOperation.getClientConnection().getLookthroughLimit(); |
| | | searchOperation.getClientConnection().getLookthroughLimit(); |
| | | |
| | | try |
| | | { |
| | |
| | | //Lookthrough limit exceeded |
| | | searchOperation.setResultCode(ResultCode.ADMIN_LIMIT_EXCEEDED); |
| | | searchOperation.appendErrorMessage( |
| | | NOTE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED.get(lookthroughLimit)); |
| | | NOTE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED.get(lookthroughLimit)); |
| | | return; |
| | | } |
| | | int cmp = dn2id.getComparator().compare(key.getData(), end); |
| | |
| | | // We have found a subordinate entry. |
| | | |
| | | EntryID entryID = new EntryID(data); |
| | | DN dn = DN.decode(new ASN1OctetString(key.getData())); |
| | | DN dn = DN.decode(ByteString.wrap(key.getData())); |
| | | |
| | | boolean isInScope = true; |
| | | if (searchScope == SearchScope.SINGLE_LEVEL) |
| | | { |
| | | // Check if this entry is an immediate child. |
| | | if ((dn.getNumComponents() != |
| | | baseDN.getNumComponents() + 1)) |
| | | baseDN.getNumComponents() + 1)) |
| | | { |
| | | isInScope = false; |
| | | } |
| | |
| | | // Try the entry cache first. Note no need to take a lock. |
| | | lockList.clear(); |
| | | cacheEntry = entryCache.getEntry(backend, entryID.longValue(), |
| | | LockType.NONE, lockList); |
| | | LockType.NONE, lockList); |
| | | |
| | | if (cacheEntry == null) |
| | | { |
| | |
| | | if (searchOperation.getFilter().matchesEntry(entry)) |
| | | { |
| | | if (pageRequest != null && |
| | | searchOperation.getEntriesSent() == |
| | | pageRequest.getSize()) |
| | | searchOperation.getEntriesSent() == |
| | | pageRequest.getSize()) |
| | | { |
| | | // The current page is full. |
| | | // Set the cookie to remember where we were. |
| | | ASN1OctetString cookie = new ASN1OctetString(key.getData()); |
| | | ByteString cookie = ByteString.wrap(key.getData()); |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), |
| | | 0, cookie); |
| | | 0, cookie); |
| | | searchOperation.getResponseControls().add(control); |
| | | return; |
| | | } |
| | |
| | | { |
| | | // Indicate no more pages. |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, |
| | | new ASN1OctetString()); |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, null); |
| | | searchOperation.getResponseControls().add(control); |
| | | } |
| | | |
| | |
| | | * processed. |
| | | */ |
| | | private void searchIndexed(EntryIDSet entryIDList, |
| | | boolean candidatesAreInScope, |
| | | SearchOperation searchOperation, |
| | | PagedResultsControl pageRequest) |
| | | throws DirectoryException, CanceledOperationException |
| | | boolean candidatesAreInScope, |
| | | SearchOperation searchOperation, |
| | | PagedResultsControl pageRequest) |
| | | throws DirectoryException, CanceledOperationException |
| | | { |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | SearchScope searchScope = searchOperation.getScope(); |
| | |
| | | |
| | | // Set the starting value. |
| | | EntryID begin = null; |
| | | if (pageRequest != null && pageRequest.getCookie().value().length != 0) |
| | | if (pageRequest != null && pageRequest.getCookie().length() != 0) |
| | | { |
| | | // The cookie contains the ID of the next entry to be returned. |
| | | try |
| | | { |
| | | begin = new EntryID(new DatabaseEntry(pageRequest.getCookie().value())); |
| | | begin = new EntryID(pageRequest.getCookie().toLong()); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | String str = StaticUtils.bytesToHex(pageRequest.getCookie().value()); |
| | | String str = pageRequest.getCookie().toHex(); |
| | | Message msg = ERR_JEB_INVALID_PAGED_RESULTS_COOKIE.get(str); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | msg, e); |
| | | msg, e); |
| | | } |
| | | } |
| | | else |
| | |
| | | |
| | | // Make sure the candidate list is smaller than the lookthrough limit |
| | | int lookthroughLimit = |
| | | searchOperation.getClientConnection().getLookthroughLimit(); |
| | | searchOperation.getClientConnection().getLookthroughLimit(); |
| | | if(lookthroughLimit > 0 && entryIDList.size() > lookthroughLimit) |
| | | { |
| | | //Lookthrough limit exceeded |
| | |
| | | // Try the entry cache first. Note no need to take a lock. |
| | | lockList.clear(); |
| | | cacheEntry = entryCache.getEntry(backend, id.longValue(), |
| | | LockType.NONE, lockList); |
| | | LockType.NONE, lockList); |
| | | |
| | | // Release any entry lock whatever happens during this block. |
| | | // (This is actually redundant since we did not take a lock). |
| | |
| | | { |
| | | // Check if this entry is an immediate child. |
| | | if ((entryDN.getNumComponents() == |
| | | baseDN.getNumComponents() + 1) && |
| | | entryDN.isDescendantOf(baseDN)) |
| | | baseDN.getNumComponents() + 1) && |
| | | entryDN.isDescendantOf(baseDN)) |
| | | { |
| | | isInScope = true; |
| | | } |
| | |
| | | else if (searchScope == SearchScope.SUBORDINATE_SUBTREE) |
| | | { |
| | | if ((entryDN.getNumComponents() > |
| | | baseDN.getNumComponents()) && |
| | | entryDN.isDescendantOf(baseDN)) |
| | | baseDN.getNumComponents()) && |
| | | entryDN.isDescendantOf(baseDN)) |
| | | { |
| | | isInScope = true; |
| | | } |
| | |
| | | if (searchOperation.getFilter().matchesEntry(entry)) |
| | | { |
| | | if (pageRequest != null && |
| | | searchOperation.getEntriesSent() == |
| | | pageRequest.getSize()) |
| | | searchOperation.getEntriesSent() == |
| | | pageRequest.getSize()) |
| | | { |
| | | // The current page is full. |
| | | // Set the cookie to remember where we were. |
| | | byte[] cookieBytes = id.getDatabaseEntry().getData(); |
| | | ASN1OctetString cookie = new ASN1OctetString(cookieBytes); |
| | | ByteString cookie = ByteString.wrap(cookieBytes); |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), |
| | | 0, cookie); |
| | | 0, cookie); |
| | | searchOperation.getResponseControls().add(control); |
| | | return; |
| | | } |
| | |
| | | // exists. However, if we have returned at least one entry or subordinate |
| | | // reference it implies the base does exist, so we can omit the check. |
| | | if (searchOperation.getEntriesSent() == 0 && |
| | | searchOperation.getReferencesSent() == 0) |
| | | searchOperation.getReferencesSent() == 0) |
| | | { |
| | | // Fetch the base entry if it exists. |
| | | Entry baseEntry = null; |
| | |
| | | { |
| | | // Indicate no more pages. |
| | | PagedResultsControl control; |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, |
| | | new ASN1OctetString()); |
| | | control = new PagedResultsControl(pageRequest.isCritical(), 0, null); |
| | | searchOperation.getResponseControls().add(control); |
| | | } |
| | | |
| | |
| | | * @throws CanceledOperationException if this operation should be cancelled. |
| | | */ |
| | | public void addEntry(Entry entry, AddOperation addOperation) |
| | | throws DatabaseException, DirectoryException, CanceledOperationException |
| | | throws DatabaseException, DirectoryException, CanceledOperationException |
| | | { |
| | | Transaction txn = beginTransaction(); |
| | | DN parentDN = getParentWithinBase(entry.getDN()); |
| | |
| | | if (dn2id.get(txn, entry.getDN(), LockMode.DEFAULT) != null) |
| | | { |
| | | Message message = |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | message); |
| | | } |
| | |
| | | { |
| | | // Do not ever expect to come through here. |
| | | Message message = |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | message); |
| | | } |
| | |
| | | { |
| | | // Do not ever expect to come through here. |
| | | Message message = |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | message); |
| | | } |
| | |
| | | { |
| | | // Do not ever expect to come through here. |
| | | Message message = |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString()); |
| | | throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | message); |
| | | } |
| | |
| | | |
| | | // Iterate up through the superior entries, starting above the parent. |
| | | for (DN dn = getParentWithinBase(parentDN); dn != null; |
| | | dn = getParentWithinBase(dn)) |
| | | dn = getParentWithinBase(dn)) |
| | | { |
| | | // Read the ID from dn2id. |
| | | EntryID nodeID = dn2id.get(txn, dn, LockMode.DEFAULT); |
| | | if (nodeID == null) |
| | | { |
| | | Message msg = |
| | | ERR_JEB_MISSING_DN2ID_RECORD.get(dn.toNormalizedString()); |
| | | ERR_JEB_MISSING_DN2ID_RECORD.get(dn.toNormalizedString()); |
| | | throw new JebException(msg); |
| | | } |
| | | |
| | |
| | | * @throws CanceledOperationException if this operation should be cancelled. |
| | | */ |
| | | public void deleteEntry(DN entryDN, DeleteOperation deleteOperation) |
| | | throws DirectoryException, DatabaseException, CanceledOperationException |
| | | throws DirectoryException, DatabaseException, CanceledOperationException |
| | | { |
| | | Transaction txn = beginTransaction(); |
| | | IndexBuffer indexBuffer = null; |
| | |
| | | // Determine whether this is a subtree delete. |
| | | boolean isSubtreeDelete = false; |
| | | |
| | | if(deleteOperation != null) |
| | | if (deleteOperation != null |
| | | && deleteOperation |
| | | .getRequestControl(SubtreeDeleteControl.DECODER) != null) |
| | | { |
| | | List<Control> controls = deleteOperation.getRequestControls(); |
| | | if (controls != null) |
| | | { |
| | | for (Control control : controls) |
| | | { |
| | | if (control.getOID().equals(OID_SUBTREE_DELETE_CONTROL)) |
| | | { |
| | | isSubtreeDelete = true; |
| | | } |
| | | } |
| | | } |
| | | isSubtreeDelete = true; |
| | | } |
| | | |
| | | /* |
| | | * We will iterate backwards through a range of the dn2id keys to |
| | | * find subordinates of the target entry from the bottom of the tree |
| | | * upwards. For example, any subordinates of "dc=example,dc=com" appear |
| | | * in dn2id with a key ending in ",dc=example,dc=com". The entry |
| | | * "cn=joe,ou=people,dc=example,dc=com" will appear after the entry |
| | | * "ou=people,dc=example,dc=com". |
| | | */ |
| | | * We will iterate backwards through a range of the dn2id keys to |
| | | * find subordinates of the target entry from the bottom of the tree |
| | | * upwards. For example, any subordinates of "dc=example,dc=com" appear |
| | | * in dn2id with a key ending in ",dc=example,dc=com". The entry |
| | | * "cn=joe,ou=people,dc=example,dc=com" will appear after the entry |
| | | * "ou=people,dc=example,dc=com". |
| | | */ |
| | | byte[] suffix = StaticUtils.getBytes("," + entryDN.toNormalizedString()); |
| | | |
| | | /* |
| | | * Set the starting value to a value of equal length but slightly |
| | | * greater than the target DN. Since keys are compared in |
| | | * reverse order we must set the first byte (the comma). |
| | | * No possibility of overflow here. |
| | | */ |
| | | * Set the starting value to a value of equal length but slightly |
| | | * greater than the target DN. Since keys are compared in |
| | | * reverse order we must set the first byte (the comma). |
| | | * No possibility of overflow here. |
| | | */ |
| | | byte[] begin = suffix.clone(); |
| | | begin[0] = (byte) (begin[0] + 1); |
| | | int subordinateEntriesDeleted = 0; |
| | |
| | | // the target entry is not a leaf. |
| | | |
| | | Message message = |
| | | ERR_JEB_DELETE_NOT_ALLOWED_ON_NONLEAF.get(entryDN.toString()); |
| | | ERR_JEB_DELETE_NOT_ALLOWED_ON_NONLEAF.get(entryDN.toString()); |
| | | throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_NONLEAF, |
| | | message); |
| | | } |
| | |
| | | } |
| | | |
| | | /* |
| | | * Delete this entry which by now must be a leaf because |
| | | * we have been deleting from the bottom of the tree upwards. |
| | | */ |
| | | * Delete this entry which by now must be a leaf because |
| | | * we have been deleting from the bottom of the tree upwards. |
| | | */ |
| | | EntryID entryID = new EntryID(data); |
| | | DN subordinateDN = DN.decode(new ASN1OctetString(key.getData())); |
| | | DN subordinateDN = DN.decode(ByteString.wrap(key.getData())); |
| | | deleteEntry(txn, indexBuffer, true, entryDN, subordinateDN, entryID); |
| | | subordinateEntriesDeleted++; |
| | | |
| | |
| | | } |
| | | |
| | | private void deleteEntry(Transaction txn, |
| | | IndexBuffer indexBuffer, |
| | | boolean manageDsaIT, |
| | | DN targetDN, |
| | | DN leafDN, |
| | | EntryID leafID) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | IndexBuffer indexBuffer, |
| | | boolean manageDsaIT, |
| | | DN targetDN, |
| | | DN leafDN, |
| | | EntryID leafID) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | { |
| | | if(leafID == null || leafDN == null) |
| | | { |
| | |
| | | if (leafID == null) |
| | | { |
| | | Message message = |
| | | ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDN.toString()); |
| | | ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDN.toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | message, matchedDN, null); |
| | |
| | | if(indexBuffer != null) |
| | | { |
| | | byte[] leafIDKeyBytes = |
| | | JebFormat.entryIDToDatabase(leafID.longValue()); |
| | | JebFormat.entryIDToDatabase(leafID.longValue()); |
| | | id2children.delete(indexBuffer, leafIDKeyBytes); |
| | | id2subtree.delete(indexBuffer, leafIDKeyBytes); |
| | | } |
| | |
| | | // Iterate up through the superior entries from the target entry. |
| | | boolean isParent = true; |
| | | for (DN parentDN = getParentWithinBase(targetDN); parentDN != null; |
| | | parentDN = getParentWithinBase(parentDN)) |
| | | parentDN = getParentWithinBase(parentDN)) |
| | | { |
| | | // Read the ID from dn2id. |
| | | EntryID parentID = dn2id.get(txn, parentDN, LockMode.DEFAULT); |
| | | if (parentID == null) |
| | | { |
| | | Message msg = |
| | | ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN.toNormalizedString()); |
| | | ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN.toNormalizedString()); |
| | | throw new JebException(msg); |
| | | } |
| | | |
| | | if(indexBuffer != null) |
| | | { |
| | | byte[] parentIDBytes = |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | // Remove from id2children. |
| | | if (isParent) |
| | | { |
| | |
| | | * determination. |
| | | */ |
| | | public boolean entryExists(DN entryDN) |
| | | throws DirectoryException |
| | | throws DirectoryException |
| | | { |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | |
| | |
| | | * @throws DatabaseException An error occurred during a database operation. |
| | | */ |
| | | public Entry getEntry(DN entryDN) |
| | | throws DatabaseException, DirectoryException |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | Entry entry = null; |
| | |
| | | // The entryID does not exist. |
| | | Message msg = ERR_JEB_MISSING_ID2ENTRY_RECORD.get(entryID.toString()); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | msg); |
| | | msg); |
| | | } |
| | | |
| | | // Put the entry in the cache making sure not to overwrite |
| | |
| | | public void replaceEntry(Entry oldEntry, Entry newEntry, |
| | | ModifyOperation modifyOperation) throws DatabaseException, |
| | | DirectoryException, CanceledOperationException |
| | | { |
| | | { |
| | | Transaction txn = beginTransaction(); |
| | | |
| | | try |
| | |
| | | { |
| | | // The entry does not exist. |
| | | Message message = |
| | | ERR_JEB_MODIFY_NO_SUCH_OBJECT.get(newEntry.getDN().toString()); |
| | | ERR_JEB_MODIFY_NO_SUCH_OBJECT.get(newEntry.getDN().toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | message, matchedDN, null); |
| | |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Moves and/or renames the provided entry in this backend, altering any |
| | |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public void renameEntry(DN currentDN, Entry entry, |
| | | ModifyDNOperation modifyDNOperation) |
| | | throws DatabaseException, DirectoryException, CanceledOperationException |
| | | ModifyDNOperation modifyDNOperation) |
| | | throws DatabaseException, DirectoryException, CanceledOperationException |
| | | { |
| | | Transaction txn = beginTransaction(); |
| | | DN oldSuperiorDN = getParentWithinBase(currentDN); |
| | |
| | | Message message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get( |
| | | entry.getDN().toString()); |
| | | throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | message); |
| | | message); |
| | | } |
| | | |
| | | EntryID oldApexID = dn2id.get(txn, currentDN, LockMode.DEFAULT); |
| | |
| | | dn2uri.targetEntryReferrals(currentDN, null); |
| | | |
| | | Message message = |
| | | ERR_JEB_MODIFYDN_NO_SUCH_OBJECT.get(currentDN.toString()); |
| | | ERR_JEB_MODIFYDN_NO_SUCH_OBJECT.get(currentDN.toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | message, matchedDN, null); |
| | |
| | | { |
| | | Message msg = ERR_JEB_MISSING_ID2ENTRY_RECORD.get(oldApexID.toString()); |
| | | throw new DirectoryException( |
| | | DirectoryServer.getServerErrorResultCode(), msg); |
| | | DirectoryServer.getServerErrorResultCode(), msg); |
| | | } |
| | | |
| | | if (!isManageDsaITOperation(modifyDNOperation)) |
| | |
| | | if (newSuperiorID == null) |
| | | { |
| | | Message msg = |
| | | ERR_JEB_NEW_SUPERIOR_NO_SUCH_OBJECT.get( |
| | | newSuperiorDN.toString()); |
| | | ERR_JEB_NEW_SUPERIOR_NO_SUCH_OBJECT.get( |
| | | newSuperiorDN.toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | msg, matchedDN, null); |
| | |
| | | |
| | | // Construct the new DN of the entry. |
| | | DN newDN = modDN(oldEntry.getDN(), |
| | | currentDN.getNumComponents(), |
| | | entry.getDN()); |
| | | currentDN.getNumComponents(), |
| | | entry.getDN()); |
| | | |
| | | // Assign a new entry ID if we are renumbering. |
| | | EntryID newID = oldID; |
| | |
| | | } |
| | | |
| | | private void renameApexEntry(Transaction txn, IndexBuffer buffer, |
| | | DN oldSuperiorDN, DN newSuperiorDN, |
| | | EntryID oldID, EntryID newID, |
| | | Entry oldEntry, Entry newEntry, |
| | | boolean isApexEntryMoved, |
| | | ModifyDNOperation modifyDNOperation) |
| | | throws DirectoryException, DatabaseException |
| | | DN oldSuperiorDN, DN newSuperiorDN, |
| | | EntryID oldID, EntryID newID, |
| | | Entry oldEntry, Entry newEntry, |
| | | boolean isApexEntryMoved, |
| | | ModifyDNOperation modifyDNOperation) |
| | | throws DirectoryException, DatabaseException |
| | | { |
| | | DN oldDN = oldEntry.getDN(); |
| | | DN newDN = newEntry.getDN(); |
| | |
| | | { |
| | | parentID = dn2id.get(txn, dn, LockMode.DEFAULT); |
| | | parentIDKeyBytes = |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | if(isParent) |
| | | { |
| | | id2children.removeID(buffer, parentIDKeyBytes, oldID); |
| | |
| | | { |
| | | parentID = dn2id.get(txn, dn, LockMode.DEFAULT); |
| | | parentIDKeyBytes = |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | if(isParent) |
| | | { |
| | | id2children.insertID(buffer, parentIDKeyBytes, newID); |
| | |
| | | } |
| | | |
| | | private void renameSubordinateEntry(Transaction txn, IndexBuffer buffer, |
| | | DN oldSuperiorDN, DN newSuperiorDN, |
| | | EntryID oldID, EntryID newID, |
| | | Entry oldEntry, DN newDN, |
| | | boolean isApexEntryMoved, |
| | | ModifyDNOperation modifyDNOperation) |
| | | throws DirectoryException, DatabaseException |
| | | DN oldSuperiorDN, DN newSuperiorDN, |
| | | EntryID oldID, EntryID newID, |
| | | Entry oldEntry, DN newDN, |
| | | boolean isApexEntryMoved, |
| | | ModifyDNOperation modifyDNOperation) |
| | | throws DirectoryException, DatabaseException |
| | | { |
| | | DN oldDN = oldEntry.getDN(); |
| | | Entry newEntry = oldEntry.duplicate(false); |
| | | newEntry.setDN(newDN); |
| | | List<Modification> modifications = |
| | | Collections.unmodifiableList(new ArrayList<Modification>(0)); |
| | | Collections.unmodifiableList(new ArrayList<Modification>(0)); |
| | | |
| | | // Create a new entry that is a copy of the old entry but with the new DN. |
| | | // Also invoke any subordinate modify DN plugins on the entry. |
| | |
| | | if (! modifyDNOperation.isSynchronizationOperation()) |
| | | { |
| | | PluginConfigManager pluginManager = |
| | | DirectoryServer.getPluginConfigManager(); |
| | | DirectoryServer.getPluginConfigManager(); |
| | | PluginResult.SubordinateModifyDN pluginResult = |
| | | pluginManager.invokeSubordinateModifyDNPlugins( |
| | | modifyDNOperation, oldEntry, newEntry, modifications); |
| | | pluginManager.invokeSubordinateModifyDNPlugins( |
| | | modifyDNOperation, oldEntry, newEntry, modifications); |
| | | |
| | | if (!pluginResult.continueProcessing()) |
| | | { |
| | |
| | | invalidReason)) |
| | | { |
| | | Message message = |
| | | ERR_JEB_MODIFYDN_ABORTED_BY_SUBORDINATE_SCHEMA_ERROR.get( |
| | | oldDN.toString(), |
| | | newDN.toString(), |
| | | invalidReason.toString()); |
| | | ERR_JEB_MODIFYDN_ABORTED_BY_SUBORDINATE_SCHEMA_ERROR.get( |
| | | oldDN.toString(), |
| | | newDN.toString(), |
| | | invalidReason.toString()); |
| | | throw new DirectoryException( |
| | | DirectoryServer.getServerErrorResultCode(), message); |
| | | } |
| | |
| | | { |
| | | EntryID parentID = dn2id.get(txn, dn, LockMode.DEFAULT); |
| | | byte[] parentIDKeyBytes = |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | id2subtree.removeID(buffer, parentIDKeyBytes, oldID); |
| | | } |
| | | } |
| | |
| | | byte[] parentIDKeyBytes; |
| | | boolean isParent = true; |
| | | for (DN superiorDN = newDN; superiorDN != null; |
| | | superiorDN = getParentWithinBase(superiorDN)) |
| | | superiorDN = getParentWithinBase(superiorDN)) |
| | | { |
| | | newParentID = dn2id.get(txn, superiorDN, LockMode.DEFAULT); |
| | | parentIDKeyBytes = |
| | | JebFormat.entryIDToDatabase(newParentID.longValue()); |
| | | JebFormat.entryIDToDatabase(newParentID.longValue()); |
| | | if(isParent) |
| | | { |
| | | id2children.insertID(buffer, parentIDKeyBytes, newID); |
| | |
| | | { |
| | | EntryID parentID = dn2id.get(txn, dn, LockMode.DEFAULT); |
| | | byte[] parentIDKeyBytes = |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | JebFormat.entryIDToDatabase(parentID.longValue()); |
| | | id2subtree.insertID(buffer, parentIDKeyBytes, newID); |
| | | } |
| | | } |
| | |
| | | public int compare(byte[] a, byte[] b) |
| | | { |
| | | for (int ai = a.length - 1, bi = b.length - 1; |
| | | ai >= 0 && bi >= 0; ai--, bi--) |
| | | ai >= 0 && bi >= 0; ai--, bi--) |
| | | { |
| | | if (a[ai] > b[bi]) |
| | | { |
| | |
| | | * @throws JebException If an error occurs in the JE backend. |
| | | */ |
| | | private void indexInsertEntry(Transaction txn, Entry entry, EntryID entryID) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | throws DatabaseException, DirectoryException, JebException |
| | | { |
| | | for (AttributeIndex index : attrIndexMap.values()) |
| | | { |
| | |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | private void indexInsertEntry(IndexBuffer buffer, Entry entry, |
| | | EntryID entryID) |
| | | throws DatabaseException, DirectoryException |
| | | EntryID entryID) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | for (AttributeIndex index : attrIndexMap.values()) |
| | | { |
| | |
| | | * @throws JebException If an error occurs in the JE backend. |
| | | */ |
| | | private void indexRemoveEntry(Transaction txn, Entry entry, EntryID entryID) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | throws DatabaseException, DirectoryException, JebException |
| | | { |
| | | for (AttributeIndex index : attrIndexMap.values()) |
| | | { |
| | |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | private void indexRemoveEntry(IndexBuffer buffer, Entry entry, |
| | | EntryID entryID) |
| | | throws DatabaseException, DirectoryException |
| | | EntryID entryID) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | for (AttributeIndex index : attrIndexMap.values()) |
| | | { |
| | |
| | | * @throws JebException If an error occurs in the JE backend. |
| | | */ |
| | | private void indexModifications(Transaction txn, Entry oldEntry, |
| | | Entry newEntry, |
| | | EntryID entryID, List<Modification> mods) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | Entry newEntry, |
| | | EntryID entryID, List<Modification> mods) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | { |
| | | // Process in index configuration order. |
| | | for (AttributeIndex index : attrIndexMap.values()) |
| | |
| | | boolean attributeModified = false; |
| | | AttributeType indexAttributeType = index.getAttributeType(); |
| | | Iterable<AttributeType> subTypes = |
| | | DirectoryServer.getSchema().getSubTypes(indexAttributeType); |
| | | DirectoryServer.getSchema().getSubTypes(indexAttributeType); |
| | | |
| | | for (Modification mod : mods) |
| | | { |
| | |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | private void indexModifications(IndexBuffer buffer, Entry oldEntry, |
| | | Entry newEntry, |
| | | EntryID entryID, List<Modification> mods) |
| | | throws DatabaseException, DirectoryException |
| | | Entry newEntry, |
| | | EntryID entryID, List<Modification> mods) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | // Process in index configuration order. |
| | | for (AttributeIndex index : attrIndexMap.values()) |
| | |
| | | boolean attributeModified = false; |
| | | AttributeType indexAttributeType = index.getAttributeType(); |
| | | Iterable<AttributeType> subTypes = |
| | | DirectoryServer.getSchema().getSubTypes(indexAttributeType); |
| | | DirectoryServer.getSchema().getSubTypes(indexAttributeType); |
| | | |
| | | for (Modification mod : mods) |
| | | { |
| | |
| | | if (entryID != null) |
| | | { |
| | | DatabaseEntry key = |
| | | new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue())); |
| | | new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue())); |
| | | EntryIDSet entryIDSet; |
| | | entryIDSet = id2subtree.readKey(key, null, LockMode.DEFAULT); |
| | | |
| | |
| | | * a new transaction. |
| | | */ |
| | | public Transaction beginTransaction() |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | Transaction parentTxn = null; |
| | | TransactionConfig txnConfig = null; |
| | |
| | | * the transaction. |
| | | */ |
| | | public static void transactionCommit(Transaction txn) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | if (txn != null) |
| | | { |
| | |
| | | * transaction. |
| | | */ |
| | | public static void transactionAbort(Transaction txn) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | if (txn != null) |
| | | { |
| | |
| | | * database. |
| | | */ |
| | | public void deleteDatabase(DatabaseContainer database) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | if(database == state) |
| | | { |
| | |
| | | * to delete the index. |
| | | */ |
| | | public void deleteAttributeIndex(AttributeIndex index) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | index.close(); |
| | | if(env.getConfig().getTransactional()) |
| | |
| | | * @throws JebException If an error occurs in the JE backend. |
| | | */ |
| | | public void setDatabasePrefix(String newDatabasePrefix) |
| | | throws DatabaseException, JebException |
| | | throws DatabaseException, JebException |
| | | |
| | | { |
| | | List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>(); |
| | |
| | | { |
| | | transactionAbort(txn); |
| | | |
| | | String msg = e.getMessage(); |
| | | if (msg == null) |
| | | { |
| | | msg = stackTraceToSingleLineString(e); |
| | | } |
| | | Message message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg); |
| | | throw new JebException(message, e); |
| | | String msg = e.getMessage(); |
| | | if (msg == null) |
| | | { |
| | | msg = stackTraceToSingleLineString(e); |
| | | } |
| | | Message message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg); |
| | | throw new JebException(message, e); |
| | | } |
| | | } |
| | | else |
| | |
| | | { |
| | | adminActionRequired = true; |
| | | Message message = |
| | | NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get( |
| | | id2children.getName()); |
| | | NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get( |
| | | id2children.getName()); |
| | | messages.add(message); |
| | | } |
| | | |
| | |
| | | { |
| | | adminActionRequired = true; |
| | | Message message = |
| | | NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get( |
| | | id2subtree.getName()); |
| | | NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get( |
| | | id2subtree.getName()); |
| | | messages.add(message); |
| | | } |
| | | } |
| | | |
| | | DataConfig entryDataConfig = |
| | | new DataConfig(cfg.isEntriesCompressed(), |
| | | cfg.isCompactEncoding(), |
| | | rootContainer.getCompressedSchema()); |
| | | new DataConfig(cfg.isEntriesCompressed(), |
| | | cfg.isCompactEncoding(), |
| | | rootContainer.getCompressedSchema()); |
| | | id2entry.setDataConfig(entryDataConfig); |
| | | |
| | | this.config = cfg; |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, |
| | | adminActionRequired, messages); |
| | | adminActionRequired, messages); |
| | | } |
| | | |
| | | /** |
| | |
| | | * configuration object. |
| | | */ |
| | | public EnvironmentConfig getEnvironmentConfig() |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | return env.getConfig(); |
| | | } |
| | |
| | | * @throws DatabaseException if a JE database error occurs. |
| | | */ |
| | | public long clearDatabase(DatabaseContainer database) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | long count = 0; |
| | | database.close(); |
| | |
| | | * @throws DatabaseException if a JE database error occurs. |
| | | */ |
| | | public long clearAttributeIndex(AttributeIndex index) |
| | | throws DatabaseException |
| | | throws DatabaseException |
| | | { |
| | | long count = 0; |
| | | |
| | |
| | | if(index.equalityIndex != null) |
| | | { |
| | | count += env.truncateDatabase(txn, index.equalityIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.presenceIndex != null) |
| | | { |
| | | count += env.truncateDatabase(txn, index.presenceIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.substringIndex != null) |
| | | { |
| | | count += env.truncateDatabase(txn, index.substringIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.orderingIndex != null) |
| | | { |
| | | count += env.truncateDatabase(txn, index.orderingIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.approximateIndex != null) |
| | | { |
| | | count += env.truncateDatabase(txn, index.approximateIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | transactionCommit(txn); |
| | | } |
| | |
| | | if(index.equalityIndex != null) |
| | | { |
| | | count += env.truncateDatabase(null, index.equalityIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.presenceIndex != null) |
| | | { |
| | | count += env.truncateDatabase(null, index.presenceIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.substringIndex != null) |
| | | { |
| | | count += env.truncateDatabase(null, index.substringIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.orderingIndex != null) |
| | | { |
| | | count += env.truncateDatabase(null, index.orderingIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | if(index.approximateIndex != null) |
| | | { |
| | | count += env.truncateDatabase(null, index.approximateIndex.getName(), |
| | | true); |
| | | true); |
| | | } |
| | | } |
| | | } |
| | |
| | | * existing entry from being performed |
| | | */ |
| | | private DN getMatchedDN(DN baseDN) |
| | | throws DirectoryException |
| | | throws DirectoryException |
| | | { |
| | | DN matchedDN = null; |
| | | DN parentDN = baseDN.getParentDNInSuffix(); |