001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.backends.pluggable; 018 019import org.forgerock.opendj.ldap.ByteSequence; 020import org.forgerock.opendj.ldap.ByteString; 021import org.forgerock.opendj.ldap.ByteStringBuilder; 022import org.forgerock.opendj.ldap.DN; 023 024/** Handles the disk representation of LDAP data. */ 025public class DnKeyFormat 026{ 027 /** The format version used by this class to encode and decode a ByteString. */ 028 static final byte FORMAT_VERSION = 0x01; 029 030 // The following fields have been copied from the DN class in the SDK 031 /** RDN separator for normalized byte string of a DN. */ 032 private static final byte NORMALIZED_RDN_SEPARATOR = 0x00; 033 /** AVA separator for normalized byte string of a DN. */ 034 private static final byte NORMALIZED_AVA_SEPARATOR = 0x01; 035 /** Escape byte for normalized byte string of a DN. */ 036 private static final byte NORMALIZED_ESC_BYTE = 0x02; 037 038 /** 039 * Find the length of bytes that represents the superior DN of the given DN 040 * key. The superior DN is represented by the initial bytes of the DN key. 041 * 042 * @param dnKey 043 * The key value of the DN. 044 * @return The length of the superior DN or -1 if the given dn is the root DN 045 * or 0 if the superior DN is removed. 046 */ 047 static int findDNKeyParent(ByteSequence dnKey) 048 { 049 if (dnKey.length() == 0) 050 { 051 // This is the root or base DN 052 return -1; 053 } 054 055 // We will walk backwards through the buffer 056 // and find the first unescaped NORMALIZED_RDN_SEPARATOR 057 for (int i = dnKey.length() - 1; i >= 0; i--) 058 { 059 if (positionIsRDNSeparator(dnKey, i)) 060 { 061 return i; 062 } 063 } 064 return 0; 065 } 066 067 /** 068 * Create a DN key from an entry DN. 069 * 070 * @param dn The entry DN. 071 * @param prefixRDNs The number of prefix RDNs to remove from the encoded 072 * representation. 073 * @return A ByteString containing the key. 074 */ 075 static ByteString dnToDNKey(DN dn, int prefixRDNs) 076 { 077 return dn.localName(dn.size() - prefixRDNs).toNormalizedByteString(); 078 } 079 080 /** 081 * Returns a best effort conversion from key to a human readable DN. 082 * @param key the index key 083 * @return a best effort conversion from key to a human readable DN. 084 */ 085 static String keyToDNString(ByteString key) 086 { 087 return key.toByteString().toASCIIString(); 088 } 089 090 private static boolean positionIsRDNSeparator(ByteSequence key, int index) 091 { 092 return index > 0 093 && key.byteAt(index) == NORMALIZED_RDN_SEPARATOR && key.byteAt(index - 1) != NORMALIZED_ESC_BYTE; 094 } 095 096 static ByteStringBuilder beforeFirstChildOf(final ByteSequence key) 097 { 098 final ByteStringBuilder beforeKey = new ByteStringBuilder(key.length() + 1); 099 beforeKey.appendBytes(key); 100 beforeKey.appendByte(NORMALIZED_RDN_SEPARATOR); 101 return beforeKey; 102 } 103 104 static ByteStringBuilder afterLastChildOf(final ByteSequence key) 105 { 106 final ByteStringBuilder afterKey = new ByteStringBuilder(key.length() + 1); 107 afterKey.appendBytes(key); 108 afterKey.appendByte(NORMALIZED_AVA_SEPARATOR); 109 return afterKey; 110 } 111 112 /** 113 * Check if two DN have a parent-child relationship. 114 * 115 * @param parent 116 * The potential parent 117 * @param child 118 * The potential child of parent 119 * @return true if child is a direct children of parent, false otherwise. 120 */ 121 static boolean isChild(ByteSequence parent, ByteSequence child) 122 { 123 if (!child.startsWith(parent)) 124 { 125 return false; 126 } 127 // Immediate children should only have one RDN separator past the parent length 128 int nbSeparator = 0; 129 for (int i = parent.length() ; i < child.length(); i++) 130 { 131 if (child.byteAt(i) == NORMALIZED_RDN_SEPARATOR) 132 { 133 nbSeparator++; 134 if (nbSeparator > 1) 135 { 136 return false; 137 } 138 } 139 } 140 return nbSeparator == 1; 141 } 142}