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