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 2009-2010 Sun Microsystems, Inc. 025 * Portions copyright 2012 ForgeRock AS. 026 */ 027 028package org.forgerock.opendj.ldap; 029 030import java.util.TreeMap; 031 032import org.forgerock.i18n.LocalizedIllegalArgumentException; 033import org.forgerock.opendj.ldap.requests.Requests; 034 035import org.forgerock.util.Reject; 036 037/** 038 * An implementation of the {@code Entry} interface which uses a {@code TreeMap} 039 * for storing attributes. Attributes are returned in ascending order of 040 * attribute description, with {@code objectClass} first, then all user 041 * attributes, and finally any operational attributes. All operations are 042 * supported by this implementation. For example, you can build an entry like 043 * this: 044 * 045 * <pre> 046 * Entry entry = new TreeMapEntry("cn=Bob,ou=People,dc=example,dc=com") 047 * .addAttribute("cn", "Bob") 048 * .addAttribute("objectclass", "top") 049 * .addAttribute("objectclass", "person") 050 * .addAttribute("objectclass", "organizationalPerson") 051 * .addAttribute("objectclass", "inetOrgPerson") 052 * .addAttribute("mail", "subgenius@example.com") 053 * .addAttribute("sn", "Dobbs"); 054 * </pre> 055 * 056 * <p> 057 * A {@code TreeMapEntry} stores references to attributes which have been added 058 * using the {@link #addAttribute} methods. Attributes sharing the same 059 * attribute description are merged by adding the values of the new attribute to 060 * the existing attribute. More specifically, the existing attribute must be 061 * modifiable for the merge to succeed. Similarly, the {@link #removeAttribute} 062 * methods remove the specified values from the existing attribute. The 063 * {@link #replaceAttribute} methods remove the existing attribute (if present) 064 * and store a reference to the new attribute - neither the new or existing 065 * attribute need to be modifiable in this case. 066 */ 067public final class TreeMapEntry extends AbstractMapEntry { 068 /** 069 * An entry factory which can be used to create new tree map entries. 070 */ 071 public static final EntryFactory FACTORY = new EntryFactory() { 072 public Entry newEntry(final DN name) { 073 return new TreeMapEntry(name); 074 } 075 }; 076 077 /** 078 * Creates an entry having the same distinguished name, attributes, and 079 * object classes of the provided entry. This constructor performs a deep 080 * copy of {@code entry} and will copy each attribute as a 081 * {@link LinkedAttribute}. 082 * <p> 083 * A shallow copy constructor is provided by {@link #TreeMapEntry(Entry)}. 084 * 085 * @param entry 086 * The entry to be copied. 087 * @return A deep copy of {@code entry}. 088 * @throws NullPointerException 089 * If {@code entry} was {@code null}. 090 * @see #TreeMapEntry(Entry) 091 */ 092 public static TreeMapEntry deepCopyOfEntry(final Entry entry) { 093 TreeMapEntry copy = new TreeMapEntry(entry.getName()); 094 for (final Attribute attribute : entry.getAllAttributes()) { 095 copy.addAttribute(new LinkedAttribute(attribute)); 096 } 097 return copy; 098 } 099 100 /** 101 * Creates an entry with an empty (root) distinguished name and no 102 * attributes. 103 */ 104 public TreeMapEntry() { 105 this(DN.rootDN()); 106 } 107 108 /** 109 * Creates an empty entry using the provided distinguished name and no 110 * attributes. 111 * 112 * @param name 113 * The distinguished name of this entry. 114 * @throws NullPointerException 115 * If {@code name} was {@code null}. 116 */ 117 public TreeMapEntry(final DN name) { 118 super(Reject.checkNotNull(name), new TreeMap<AttributeDescription, Attribute>()); 119 } 120 121 /** 122 * Creates an entry having the same distinguished name, attributes, and 123 * object classes of the provided entry. This constructor performs a shallow 124 * copy of {@code entry} and will not copy the attributes contained in 125 * {@code entry}. 126 * <p> 127 * A deep copy constructor is provided by {@link #deepCopyOfEntry(Entry)} 128 * 129 * @param entry 130 * The entry to be copied. 131 * @throws NullPointerException 132 * If {@code entry} was {@code null}. 133 * @see #deepCopyOfEntry(Entry) 134 */ 135 public TreeMapEntry(final Entry entry) { 136 this(entry.getName()); 137 for (final Attribute attribute : entry.getAllAttributes()) { 138 addAttribute(attribute); 139 } 140 } 141 142 /** 143 * Creates an empty entry using the provided distinguished name decoded 144 * using the default schema. 145 * 146 * @param name 147 * The distinguished name of this entry. 148 * @throws LocalizedIllegalArgumentException 149 * If {@code name} could not be decoded using the default 150 * schema. 151 * @throws NullPointerException 152 * If {@code name} was {@code null}. 153 */ 154 public TreeMapEntry(final String name) { 155 this(DN.valueOf(name)); 156 } 157 158 /** 159 * Creates a new entry using the provided lines of LDIF decoded using the 160 * default schema. 161 * 162 * @param ldifLines 163 * Lines of LDIF containing the an LDIF add change record or an 164 * LDIF entry record. 165 * @throws LocalizedIllegalArgumentException 166 * If {@code ldifLines} was empty, or contained invalid LDIF, or 167 * could not be decoded using the default schema. 168 * @throws NullPointerException 169 * If {@code ldifLines} was {@code null} . 170 */ 171 public TreeMapEntry(final String... ldifLines) { 172 this(Requests.newAddRequest(ldifLines)); 173 } 174 175}