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 028 // The following fields have been copied from the DN class in the SDK 029 /** RDN separator for normalized byte string of a DN. */ 030 private static final byte NORMALIZED_RDN_SEPARATOR = 0x00; 031 /** AVA separator for normalized byte string of a DN. */ 032 private static final byte NORMALIZED_AVA_SEPARATOR = 0x01; 033 /** Escape byte for normalized byte string of a DN. */ 034 private static final byte NORMALIZED_ESC_BYTE = 0x02; 035 036 /** 037 * Find the length of bytes that represents the superior DN of the given DN 038 * key. The superior DN is represented by the initial bytes of the DN key. 039 * 040 * @param dnKey 041 * The key value of the DN. 042 * @return The length of the superior DN or -1 if the given dn is the root DN 043 * or 0 if the superior DN is removed. 044 */ 045 static int findDNKeyParent(ByteSequence dnKey) 046 { 047 if (dnKey.length() == 0) 048 { 049 // This is the root or base DN 050 return -1; 051 } 052 053 // We will walk backwards through the buffer 054 // and find the first unescaped NORMALIZED_RDN_SEPARATOR 055 for (int i = dnKey.length() - 1; i >= 0; i--) 056 { 057 if (positionIsRDNSeparator(dnKey, i)) 058 { 059 return i; 060 } 061 } 062 return 0; 063 } 064 065 /** 066 * Create a DN key from an entry DN. 067 * 068 * @param dn The entry DN. 069 * @param prefixRDNs The number of prefix RDNs to remove from the encoded 070 * representation. 071 * @return A ByteString containing the key. 072 */ 073 static ByteString dnToDNKey(DN dn, int prefixRDNs) 074 { 075 return dn.localName(dn.size() - prefixRDNs).toNormalizedByteString(); 076 } 077 078 /** 079 * Returns a best effort conversion from key to a human readable DN. 080 * @param key the index key 081 * @return a best effort conversion from key to a human readable DN. 082 */ 083 static String keyToDNString(ByteString key) 084 { 085 return key.toByteString().toASCIIString(); 086 } 087 088 private static boolean positionIsRDNSeparator(ByteSequence key, int index) 089 { 090 return index > 0 091 && key.byteAt(index) == NORMALIZED_RDN_SEPARATOR && key.byteAt(index - 1) != NORMALIZED_ESC_BYTE; 092 } 093 094 static ByteStringBuilder beforeFirstChildOf(final ByteSequence key) 095 { 096 final ByteStringBuilder beforeKey = new ByteStringBuilder(key.length() + 1); 097 beforeKey.appendBytes(key); 098 beforeKey.appendByte(NORMALIZED_RDN_SEPARATOR); 099 return beforeKey; 100 } 101 102 static ByteStringBuilder afterLastChildOf(final ByteSequence key) 103 { 104 final ByteStringBuilder afterKey = new ByteStringBuilder(key.length() + 1); 105 afterKey.appendBytes(key); 106 afterKey.appendByte(NORMALIZED_AVA_SEPARATOR); 107 return afterKey; 108 } 109 110 /** 111 * Check if two DN have a parent-child relationship. 112 * 113 * @param parent 114 * The potential parent 115 * @param child 116 * The potential child of parent 117 * @return true if child is a direct children of parent, false otherwise. 118 */ 119 static boolean isChild(ByteSequence parent, ByteSequence child) 120 { 121 if (child.length() <= parent.length() 122 || child.byteAt(parent.length()) != NORMALIZED_RDN_SEPARATOR 123 || !child.startsWith(parent)) 124 { 125 return false; 126 } 127 // Immediate children should only have one RDN separator past the parent length 128 boolean childSeparatorDetected = false; 129 for (int i = parent.length() ; i < child.length(); i++) 130 { 131 if (child.byteAt(i) == NORMALIZED_RDN_SEPARATOR) 132 { 133 if (childSeparatorDetected) 134 { 135 return false; 136 } 137 childSeparatorDetected = true; 138 } 139 } 140 return childSeparatorDetected; 141 } 142}