MemoryBackend.java revision 54fbe518d8e0f66c95a8825209d6a176dcb323a1
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
/**
* This class defines a very simple backend that stores its information in
* memory. This is primarily intended for testing purposes with small data
* sets, as it does not have any indexing mechanism such as would be required to
* achieve high performance with large data sets. It is also heavily
* synchronized for simplicity at the expense of performance, rather than
* providing a more fine-grained locking mechanism.
* <BR><BR>
* Entries stored in this backend are held in a
* <CODE>LinkedHashMap<DN,Entry></CODE> object, which ensures that the
* order in which you iterate over the entries is the same as the order in which
* they were inserted. By combining this with the constraint that no entry can
* be added before its parent, you can ensure that iterating through the entries
* will always process the parent entries before their children, which is
* important for both search result processing and LDIF exports.
* <BR><BR>
* As mentioned above, no data indexing is performed, so all non-baseObject
* searches require iteration through the entire data set. If this is to become
* a more general-purpose backend, then additional
* <CODE>HashMap<ByteString,Set<DN>></CODE> objects could be used
* to provide that capability.
* <BR><BR>
* There is actually one index that does get maintained within this backend,
* which is a mapping between the DN of an entry and the DNs of any immediate
* children of that entry. This is needed to efficiently determine whether an
* entry has any children (which must not be the case for delete operations).
*/
public class MemoryBackend
extends Backend<MemoryBackendCfg>
{
/** The base DNs for this backend. */
/** The mapping between parent DNs and their immediate children. */
/** The base DNs for this backend, in a hash set. */
/** The set of supported controls for this backend. */
/** The mapping between entry DNs and the corresponding entries. */
/**
* Creates a new backend with the provided information. All backend
* implementations must implement a default constructor that use
* <CODE>super()</CODE> to invoke this constructor.
*/
public MemoryBackend()
{
super();
// Perform all initialization in initializeBackend.
}
/**
* Set the base DNs for this backend. This is used by the unit tests
* to set the base DNs without having to provide a configuration
* object when initializing the backend.
* @param baseDNs The set of base DNs to be served by this memory backend.
*/
{
}
/** {@inheritDoc} */
public void configureBackend(MemoryBackendCfg config, ServerContext serverContext) throws ConfigException
{
{
}
}
/** {@inheritDoc} */
public synchronized void initializeBackend()
{
// We won't support anything other than exactly one base DN in this
// implementation. If we were to add such support in the future, we would
// likely want to separate the data for each base DN into a separate entry
// map.
{
throw new ConfigException(message);
}
{
}
{
try
{
}
catch (Exception e)
{
logger.traceException(e);
dn, getExceptionMessage(e));
throw new InitializationException(message, e);
}
}
}
/**
* Removes any data that may have been stored in this backend.
*/
public synchronized void clearMemoryBackend()
{
}
/** {@inheritDoc} */
public synchronized void finalizeBackend()
{
{
try
{
}
catch (Exception e)
{
logger.traceException(e);
}
}
}
/** {@inheritDoc} */
public DN[] getBaseDNs()
{
return baseDNs;
}
/** {@inheritDoc} */
public synchronized long getEntryCount()
{
{
}
return -1;
}
/** {@inheritDoc} */
{
// All searches in this backend will always be considered indexed.
return true;
}
/** {@inheritDoc} */
throws DirectoryException
{
if(ret < 0)
{
return ConditionResult.UNDEFINED;
}
}
/** {@inheritDoc} */
throws DirectoryException
{
// Try to look up the immediate children for the DN
{
{
// The entry does exist but just no children.
return 0;
}
return -1;
}
if(!subtree)
{
}
else
{
long count = 0;
{
count++;
}
return count;
}
}
/** {@inheritDoc} */
{
{
}
return entry;
}
/** {@inheritDoc} */
{
}
/** {@inheritDoc} */
throws DirectoryException
{
// See if the target entry already exists. If so, then fail.
{
}
// If the entry is one of the base DNs, then add it.
{
return;
}
// Get the parent DN and ensure that it exists in the backend.
{
}
{
}
{
}
}
/** {@inheritDoc} */
throws DirectoryException
{
// Make sure the entry exists. If not, then throw an exception.
{
}
// Check to see if the entry contains a subtree delete control.
if (subtreeDelete)
{
{
{
try
{
}
catch (Exception e)
{
// This shouldn't happen, but we want the delete to continue anyway
// so just ignore it if it does for some reason.
logger.traceException(e);
}
}
}
}
else
{
// Make sure the entry doesn't have any children. If it does, then throw
// an exception.
{
}
}
// Remove the entry from the backend. Also remove the reference to it from
// its parent, if applicable.
{
if (parentsChildren != null)
{
if (parentsChildren.isEmpty())
{
}
}
}
}
/** {@inheritDoc} */
{
// Make sure the entry exists. If not, then throw an exception.
{
}
// Replace the old entry with the new one.
}
/** {@inheritDoc} */
throws DirectoryException
{
// Make sure that the target entry exists.
{
}
// Make sure that the target entry doesn't have any children.
{
{
}
else
{
}
}
// Make sure that no entry exists with the new DN.
{
}
// Make sure that the new DN is in this backend.
boolean matchFound = false;
{
{
matchFound = true;
break;
}
}
if (! matchFound)
{
}
// Make sure that the parent of the new entry exists.
{
}
// Delete the current entry and add the new one.
}
/** {@inheritDoc} */
throws DirectoryException
{
// Get the base DN, scope, and filter for the search.
// Make sure the base entry exists if it's supposed to be in this backend.
{
{
{
break;
}
}
throw new DirectoryException(
}
{
}
// If it's a base-level search, then just get that entry and return it if it
// matches the filter.
{
{
}
}
else
{
// Walk through all entries and send the ones that match.
{
e = e.duplicate(true);
{
}
}
}
}
/** {@inheritDoc} */
{
return supportedControls;
}
/** {@inheritDoc} */
{
return Collections.emptySet();
}
/** {@inheritDoc} */
{
switch (backendOperation)
{
case LDIF_EXPORT:
case LDIF_IMPORT:
return true;
default:
return false;
}
}
/** {@inheritDoc} */
throws DirectoryException
{
// Create the LDIF writer.
try
{
}
catch (Exception e)
{
logger.traceException(e);
}
// Walk through all the entries and write them to LDIF.
try
{
{
}
}
catch (Exception e)
{
}
finally
{
}
}
/** {@inheritDoc} */
throws DirectoryException
{
try
{
}
catch (Exception e)
{
}
try
{
while (true)
{
try
{
if (e == null)
{
break;
}
}
catch (LDIFException le)
{
if (! le.canContinueReading())
{
}
else
{
continue;
}
}
try
{
}
catch (DirectoryException de)
{
}
}
}
catch (DirectoryException de)
{
throw de;
}
catch (Exception e)
{
}
finally
{
}
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
throws DirectoryException
{
}
/** {@inheritDoc} */
public void preloadEntryCache() throws UnsupportedOperationException {
throw new UnsupportedOperationException("Operation not supported.");
}
}