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