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