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 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.types; 028 029import java.util.Collection; 030import java.util.Set; 031 032import org.forgerock.opendj.ldap.ByteString; 033import org.forgerock.opendj.ldap.DecodeException; 034import org.forgerock.opendj.ldap.schema.MatchingRule; 035 036import static org.opends.server.util.StaticUtils.*; 037 038/** An abstract base class for implementing new types of {@link Attribute}. */ 039@org.opends.server.types.PublicAPI( 040 stability = org.opends.server.types.StabilityLevel.UNCOMMITTED, 041 mayInstantiate = false, 042 mayExtend = false, 043 mayInvoke = true) 044public abstract class AbstractAttribute implements Attribute 045{ 046 /** Creates a new abstract attribute. */ 047 protected AbstractAttribute() 048 { 049 // No implementation required. 050 } 051 052 /** 053 * {@inheritDoc} 054 * <p> 055 * This implementation iterates through each attribute value in the 056 * provided collection, checking to see if this attribute contains 057 * the value using {@link #contains(ByteString)}. 058 */ 059 @Override 060 public boolean containsAll(Collection<ByteString> values) 061 { 062 for (ByteString value : values) 063 { 064 if (!contains(value)) 065 { 066 return false; 067 } 068 } 069 return true; 070 } 071 072 @Override 073 public final boolean equals(Object o) 074 { 075 if (this == o) 076 { 077 return true; 078 } 079 if (!(o instanceof Attribute)) 080 { 081 return false; 082 } 083 084 Attribute a = (Attribute) o; 085 return getAttributeType().equals(a.getAttributeType()) 086 && valuesEqual(a) 087 && optionsEqual(a.getOptions()); 088 } 089 090 private boolean valuesEqual(Attribute a) 091 { 092 if (size() != a.size()) 093 { 094 return false; 095 } 096 097 for (ByteString v : a) 098 { 099 if (!contains(v)) 100 { 101 return false; 102 } 103 } 104 return true; 105 } 106 107 /** 108 * {@inheritDoc} 109 * <p> 110 * This implementation returns the primary name associated with this 111 * attribute's attribute type or, if there is no primary name, the 112 * attribute type's OID. 113 */ 114 @Override 115 public String getName() 116 { 117 return getAttributeType().getNameOrOID(); 118 } 119 120 /** 121 * {@inheritDoc} 122 * <p> 123 * This implementation returns this attribute's name if there are no 124 * attribute options, otherwise it constructs a string comprising of 125 * this attribute's name followed by a semi-colon and a semi-colon 126 * separated list of its attribute options. 127 */ 128 @Override 129 public String getNameWithOptions() 130 { 131 if (!hasOptions()) 132 { 133 return getName(); 134 } 135 136 StringBuilder buffer = new StringBuilder(); 137 buffer.append(getName()); 138 for (String option : getOptions()) 139 { 140 buffer.append(';'); 141 buffer.append(option); 142 } 143 return buffer.toString(); 144 } 145 146 /** 147 * {@inheritDoc} 148 * <p> 149 * This implementation returns <code>true</code> if the provided 150 * collection of options is <code>null</code> or empty. If the 151 * collection is non-empty and this attribute does not have any 152 * options then it returns <code>false</code>. Otherwise, each 153 * option in the provided collection is checked using 154 * {@link #hasOption(String)} and <code>true</code> is 155 * returned if all the provided options are present. 156 */ 157 @Override 158 public boolean hasAllOptions(Collection<String> options) 159 { 160 if (options == null || options.isEmpty()) 161 { 162 return true; 163 } 164 165 if (hasOptions()) 166 { 167 return hasAllOptions0(options); 168 } 169 return false; 170 } 171 172 @Override 173 public int hashCode() 174 { 175 int hashCode = getAttributeType().hashCode(); 176 for (ByteString value : this) 177 { 178 try 179 { 180 MatchingRule eqRule = getAttributeType().getEqualityMatchingRule(); 181 hashCode += eqRule.normalizeAttributeValue(value).hashCode(); 182 } 183 catch (DecodeException e) 184 { 185 hashCode += value.hashCode(); 186 } 187 } 188 return hashCode; 189 } 190 191 /** 192 * {@inheritDoc} 193 * <p> 194 * This implementation calls {@link #getOptions()} to 195 * retrieve this attribute's set of options and then compares them 196 * one at a time against the provided option. All comparisons are 197 * case insensitive (this is why we iterate through the set of 198 * options, rather than doing a simpler set membership test). 199 */ 200 @Override 201 public boolean hasOption(String option) 202 { 203 String noption = toLowerCase(option); 204 205 // Cannot use Set.contains() because the options are not normalized. 206 for (String o : getOptions()) 207 { 208 String no = toLowerCase(o); 209 if (no.equals(noption)) 210 { 211 return true; 212 } 213 } 214 return false; 215 } 216 217 /** 218 * {@inheritDoc} 219 * <p> 220 * This implementation retrieves the set of options associated with 221 * this attribute and tests to see if it is empty. 222 */ 223 @Override 224 public boolean hasOptions() 225 { 226 return !getOptions().isEmpty(); 227 } 228 229 /** 230 * {@inheritDoc} 231 * <p> 232 * This implementation returns <code>true</code> if the 233 * {@link #size()} of this attribute is zero. 234 */ 235 @Override 236 public boolean isEmpty() 237 { 238 return size() == 0; 239 } 240 241 @Override 242 public boolean isReal() 243 { 244 return !isVirtual(); 245 } 246 247 /** 248 * {@inheritDoc} 249 * <p> 250 * This implementation returns !{@link #hasOptions()} if the 251 * provided set of options is <code>null</code>. Otherwise it 252 * checks that the size of the provided set of options is equal to 253 * the size of this attribute's options, return <code>false</code> 254 * if the sizes differ. If the sizes are the same then each option 255 * in the provided set is checked using 256 * {@link #hasOption(String)} and <code>true</code> is 257 * returned if all the provided options are present. 258 */ 259 @Override 260 public boolean optionsEqual(Set<String> options) 261 { 262 if (options == null) 263 { 264 return !hasOptions(); 265 } 266 267 if (getOptions().size() == options.size()) 268 { 269 return hasAllOptions0(options); 270 } 271 return false; 272 } 273 274 /** Cannot use Set.containsAll() because the set of options are not normalized. */ 275 private boolean hasAllOptions0(Collection<String> options) 276 { 277 for (String option : options) 278 { 279 if (!hasOption(option)) 280 { 281 return false; 282 } 283 } 284 return true; 285 } 286 287 @Override 288 public final String toString() 289 { 290 StringBuilder buffer = new StringBuilder(); 291 toString(buffer); 292 return buffer.toString(); 293 } 294}