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