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