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