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 static org.forgerock.opendj.ldap.Attributes.emptyAttribute; 021 022import java.util.Collection; 023import java.util.Iterator; 024 025import com.forgerock.opendj.util.Iterables; 026import com.forgerock.opendj.util.Predicate; 027import org.forgerock.util.Reject; 028 029/** 030 * This class provides a skeletal implementation of the {@code Entry} interface, 031 * to minimize the effort required to implement this interface. 032 */ 033public abstract class AbstractEntry implements Entry { 034 035 /** Predicate used for findAttributes. */ 036 private static final Predicate<Attribute, AttributeDescription> FIND_ATTRIBUTES_PREDICATE = 037 new Predicate<Attribute, AttributeDescription>() { 038 039 @Override 040 public boolean matches(final Attribute value, final AttributeDescription p) { 041 return value.getAttributeDescription().isSubTypeOf(p); 042 } 043 044 }; 045 046 /** 047 * Sole constructor. 048 */ 049 protected AbstractEntry() { 050 // No implementation required. 051 } 052 053 @Override 054 public boolean addAttribute(final Attribute attribute) { 055 return addAttribute(attribute, null); 056 } 057 058 @Override 059 public Entry addAttribute(final String attributeDescription, final Object... values) { 060 addAttribute(new LinkedAttribute(attributeDescription, values), null); 061 return this; 062 } 063 064 @Override 065 public boolean containsAttribute(final Attribute attribute, 066 final Collection<? super ByteString> missingValues) { 067 final Attribute a = getAttribute(attribute.getAttributeDescription()); 068 if (a == null) { 069 if (missingValues != null) { 070 missingValues.addAll(attribute); 071 } 072 return false; 073 } else { 074 boolean result = true; 075 for (final ByteString value : attribute) { 076 if (!a.contains(value)) { 077 if (missingValues != null) { 078 missingValues.add(value); 079 } 080 result = false; 081 } 082 } 083 return result; 084 } 085 } 086 087 @Override 088 public boolean containsAttribute(final String attributeDescription, final Object... values) { 089 return containsAttribute(new LinkedAttribute(attributeDescription, values), null); 090 } 091 092 @Override 093 public boolean equals(final Object object) { 094 if (this == object) { 095 return true; 096 } else if (object instanceof Entry) { 097 final Entry other = (Entry) object; 098 if (!getName().equals(other.getName())) { 099 return false; 100 } 101 // Distinguished name is the same, compare attributes. 102 if (getAttributeCount() != other.getAttributeCount()) { 103 return false; 104 } 105 for (final Attribute attribute : getAllAttributes()) { 106 final Attribute otherAttribute = 107 other.getAttribute(attribute.getAttributeDescription()); 108 if (!attribute.equals(otherAttribute)) { 109 return false; 110 } 111 } 112 return true; 113 } else { 114 return false; 115 } 116 } 117 118 @Override 119 public Iterable<Attribute> getAllAttributes(final AttributeDescription attributeDescription) { 120 Reject.ifNull(attributeDescription); 121 122 return Iterables.filteredIterable(getAllAttributes(), FIND_ATTRIBUTES_PREDICATE, 123 attributeDescription); 124 } 125 126 @Override 127 public Iterable<Attribute> getAllAttributes(final String attributeDescription) { 128 return getAllAttributes(AttributeDescription.valueOf(attributeDescription)); 129 } 130 131 @Override 132 public Attribute getAttribute(final AttributeDescription attributeDescription) { 133 for (final Attribute attribute : getAllAttributes()) { 134 final AttributeDescription ad = attribute.getAttributeDescription(); 135 if (isAssignable(attributeDescription, ad)) { 136 return attribute; 137 } 138 } 139 return null; 140 } 141 142 @Override 143 public Attribute getAttribute(final String attributeDescription) { 144 return getAttribute(AttributeDescription.valueOf(attributeDescription)); 145 } 146 147 @Override 148 public int hashCode() { 149 int hashCode = getName().hashCode(); 150 for (final Attribute attribute : getAllAttributes()) { 151 hashCode += attribute.hashCode(); 152 } 153 return hashCode; 154 } 155 156 @Override 157 public AttributeParser parseAttribute(final AttributeDescription attributeDescription) { 158 final Attribute attribute = getAttribute(attributeDescription); 159 return AttributeParser.parseAttribute(attribute != null ? attribute : emptyAttribute(attributeDescription)); 160 } 161 162 @Override 163 public AttributeParser parseAttribute(final String attributeDescription) { 164 final Attribute attribute = getAttribute(attributeDescription); 165 return AttributeParser.parseAttribute(attribute != null ? attribute : emptyAttribute(attributeDescription)); 166 } 167 168 @Override 169 public boolean removeAttribute(final Attribute attribute, 170 final Collection<? super ByteString> missingValues) { 171 final Iterator<Attribute> i = getAllAttributes().iterator(); 172 final AttributeDescription attributeDescription = attribute.getAttributeDescription(); 173 while (i.hasNext()) { 174 final Attribute oldAttribute = i.next(); 175 if (isAssignable(attributeDescription, oldAttribute.getAttributeDescription())) { 176 if (attribute.isEmpty()) { 177 i.remove(); 178 return true; 179 } else { 180 final boolean modified = oldAttribute.removeAll(attribute, missingValues); 181 if (oldAttribute.isEmpty()) { 182 i.remove(); 183 return true; 184 } 185 return modified; 186 } 187 } 188 } 189 // Not found. 190 if (missingValues != null) { 191 missingValues.addAll(attribute); 192 } 193 return false; 194 } 195 196 @Override 197 public boolean removeAttribute(final AttributeDescription attributeDescription) { 198 return removeAttribute(emptyAttribute(attributeDescription), null); 199 } 200 201 @Override 202 public Entry removeAttribute(final String attributeDescription, final Object... values) { 203 removeAttribute(new LinkedAttribute(attributeDescription, values), null); 204 return this; 205 } 206 207 @Override 208 public boolean replaceAttribute(final Attribute attribute) { 209 if (attribute.isEmpty()) { 210 return removeAttribute(attribute.getAttributeDescription()); 211 } else { 212 /* 213 * For consistency with addAttribute and removeAttribute, preserve 214 * the existing attribute if it already exists. 215 */ 216 final Attribute oldAttribute = getAttribute(attribute.getAttributeDescription()); 217 if (oldAttribute != null) { 218 oldAttribute.clear(); 219 oldAttribute.addAll(attribute); 220 } else { 221 addAttribute(attribute, null); 222 } 223 return true; 224 } 225 } 226 227 @Override 228 public Entry replaceAttribute(final String attributeDescription, final Object... values) { 229 replaceAttribute(new LinkedAttribute(attributeDescription, values)); 230 return this; 231 } 232 233 @Override 234 public Entry setName(final String dn) { 235 return setName(DN.valueOf(dn)); 236 } 237 238 @Override 239 public String toString() { 240 return Entries.toLDIF(this); 241 } 242 243 private boolean isAssignable(final AttributeDescription from, final AttributeDescription to) { 244 if (!from.isPlaceHolder()) { 245 return from.equals(to); 246 } else { 247 return from.matches(to); 248 } 249 } 250 251}