/*
|
* The contents of this file are subject to the terms of the Common Development and
|
* Distribution License (the License). You may not use this file except in compliance with the
|
* License.
|
*
|
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
|
* specific language governing permission and limitations under the License.
|
*
|
* When distributing Covered Software, include this CDDL Header Notice in each file and include
|
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
|
* Header, with the fields enclosed by brackets [] replaced by your own identifying
|
* information: "Portions Copyright [year] [name of copyright owner]".
|
*
|
* Copyright 2006-2010 Sun Microsystems, Inc.
|
* Portions Copyright 2014-2016 ForgeRock AS.
|
*/
|
package org.opends.server.backends.pluggable;
|
|
import org.forgerock.opendj.ldap.ByteSequence;
|
import org.forgerock.opendj.ldap.ByteString;
|
import org.forgerock.opendj.ldap.ByteStringBuilder;
|
import org.forgerock.opendj.ldap.DN;
|
|
/** Handles the disk representation of LDAP data. */
|
public class DnKeyFormat
|
{
|
|
// The following fields have been copied from the DN class in the SDK
|
/** RDN separator for normalized byte string of a DN. */
|
private static final byte NORMALIZED_RDN_SEPARATOR = 0x00;
|
/** AVA separator for normalized byte string of a DN. */
|
private static final byte NORMALIZED_AVA_SEPARATOR = 0x01;
|
/** Escape byte for normalized byte string of a DN. */
|
private static final byte NORMALIZED_ESC_BYTE = 0x02;
|
|
/**
|
* Find the length of bytes that represents the superior DN of the given DN
|
* key. The superior DN is represented by the initial bytes of the DN key.
|
*
|
* @param dnKey
|
* The key value of the DN.
|
* @return The length of the superior DN or -1 if the given dn is the root DN
|
* or 0 if the superior DN is removed.
|
*/
|
static int findDNKeyParent(ByteSequence dnKey)
|
{
|
if (dnKey.length() == 0)
|
{
|
// This is the root or base DN
|
return -1;
|
}
|
|
// We will walk backwards through the buffer
|
// and find the first unescaped NORMALIZED_RDN_SEPARATOR
|
for (int i = dnKey.length() - 1; i >= 0; i--)
|
{
|
if (positionIsRDNSeparator(dnKey, i))
|
{
|
return i;
|
}
|
}
|
return 0;
|
}
|
|
/**
|
* Create a DN key from an entry DN.
|
*
|
* @param dn The entry DN.
|
* @param prefixRDNs The number of prefix RDNs to remove from the encoded
|
* representation.
|
* @return A ByteString containing the key.
|
*/
|
static ByteString dnToDNKey(DN dn, int prefixRDNs)
|
{
|
return dn.localName(dn.size() - prefixRDNs).toNormalizedByteString();
|
}
|
|
/**
|
* Returns a best effort conversion from key to a human readable DN.
|
* @param key the index key
|
* @return a best effort conversion from key to a human readable DN.
|
*/
|
static String keyToDNString(ByteString key)
|
{
|
return key.toByteString().toASCIIString();
|
}
|
|
private static boolean positionIsRDNSeparator(ByteSequence key, int index)
|
{
|
return index > 0
|
&& key.byteAt(index) == NORMALIZED_RDN_SEPARATOR && key.byteAt(index - 1) != NORMALIZED_ESC_BYTE;
|
}
|
|
static ByteStringBuilder beforeFirstChildOf(final ByteSequence key)
|
{
|
final ByteStringBuilder beforeKey = new ByteStringBuilder(key.length() + 1);
|
beforeKey.appendBytes(key);
|
beforeKey.appendByte(NORMALIZED_RDN_SEPARATOR);
|
return beforeKey;
|
}
|
|
static ByteStringBuilder afterLastChildOf(final ByteSequence key)
|
{
|
final ByteStringBuilder afterKey = new ByteStringBuilder(key.length() + 1);
|
afterKey.appendBytes(key);
|
afterKey.appendByte(NORMALIZED_AVA_SEPARATOR);
|
return afterKey;
|
}
|
|
/**
|
* Check if two DN have a parent-child relationship.
|
*
|
* @param parent
|
* The potential parent
|
* @param child
|
* The potential child of parent
|
* @return true if child is a direct children of parent, false otherwise.
|
*/
|
static boolean isChild(ByteSequence parent, ByteSequence child)
|
{
|
if (!child.startsWith(parent))
|
{
|
return false;
|
}
|
// Immediate children should only have one RDN separator past the parent length
|
int nbSeparator = 0;
|
for (int i = parent.length() ; i < child.length(); i++)
|
{
|
if (child.byteAt(i) == NORMALIZED_RDN_SEPARATOR)
|
{
|
nbSeparator++;
|
if (nbSeparator > 1)
|
{
|
return false;
|
}
|
}
|
}
|
return nbSeparator == 1;
|
}
|
}
|