001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.shared.ldap.entry; 021 022 import org.apache.directory.shared.ldap.exception.LdapException; 023 024 import org.apache.directory.shared.i18n.I18n; 025 import org.apache.directory.shared.ldap.schema.AttributeType; 026 import org.apache.directory.shared.ldap.schema.LdapComparator; 027 import org.apache.directory.shared.ldap.schema.MatchingRule; 028 import org.apache.directory.shared.ldap.schema.Normalizer; 029 import org.apache.directory.shared.ldap.schema.SyntaxChecker; 030 import org.slf4j.Logger; 031 import org.slf4j.LoggerFactory; 032 033 034 /** 035 * A wrapper around byte[] values in entries. 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 * @version $Rev$, $Date$ 039 */ 040 public abstract class AbstractValue<T> implements Value<T> 041 { 042 /** logger for reporting errors that might not be handled properly upstream */ 043 private static final Logger LOG = LoggerFactory.getLogger( AbstractValue.class ); 044 045 /** reference to the attributeType zssociated with the value */ 046 protected transient AttributeType attributeType; 047 048 /** the wrapped binary value */ 049 protected T wrappedValue; 050 051 /** the canonical representation of the wrapped value */ 052 protected T normalizedValue; 053 054 /** A flag set when the value has been normalized */ 055 protected boolean normalized; 056 057 /** cached results of the isValid() method call */ 058 protected Boolean valid; 059 060 /** A flag set if the normalized data is different from the wrapped data */ 061 protected transient boolean same; 062 063 /** 064 * {@inheritDoc} 065 */ 066 public Value<T> clone() 067 { 068 try 069 { 070 return (Value<T>)super.clone(); 071 } 072 catch ( CloneNotSupportedException cnse ) 073 { 074 // Do nothing 075 return null; 076 } 077 } 078 079 080 /** 081 * Gets a reference to the wrapped binary value. 082 * 083 * Warning ! The value is not copied !!! 084 * 085 * @return a direct handle on the binary value that is wrapped 086 */ 087 public T getReference() 088 { 089 return wrappedValue; 090 } 091 092 093 /** 094 * Get the associated AttributeType 095 * @return The AttributeType 096 */ 097 public AttributeType getAttributeType() 098 { 099 return attributeType; 100 } 101 102 103 public void apply( AttributeType attributeType ) 104 { 105 if ( this.attributeType != null ) 106 { 107 if ( !attributeType.equals( this.attributeType ) ) 108 { 109 throw new IllegalArgumentException( I18n.err( I18n.ERR_04476, attributeType.getName(), this.attributeType.getName() ) ); 110 } 111 else 112 { 113 return; 114 } 115 } 116 117 this.attributeType = attributeType; 118 119 try 120 { 121 normalize(); 122 } 123 catch ( LdapException ne ) 124 { 125 String message = I18n.err( I18n.ERR_04447, ne.getLocalizedMessage() ); 126 LOG.info( message ); 127 normalized = false; 128 } 129 } 130 131 132 /** 133 * Gets a comparator using getMatchingRule() to resolve the matching 134 * that the comparator is extracted from. 135 * 136 * @return a comparator associated with the attributeType or null if one cannot be found 137 * @throws LdapException if resolution of schema entities fail 138 */ 139 protected LdapComparator<T> getLdapComparator() throws LdapException 140 { 141 if ( attributeType != null ) 142 { 143 MatchingRule mr = getMatchingRule(); 144 145 if ( mr == null ) 146 { 147 return null; 148 } 149 150 return (LdapComparator<T>)mr.getLdapComparator(); 151 } 152 else 153 { 154 return null; 155 } 156 } 157 158 159 /** 160 * Find a matchingRule to use for normalization and comparison. If an equality 161 * matchingRule cannot be found it checks to see if other matchingRules are 162 * available: SUBSTR, and ORDERING. If a matchingRule cannot be found null is 163 * returned. 164 * 165 * @return a matchingRule or null if one cannot be found for the attributeType 166 * @throws LdapException if resolution of schema entities fail 167 */ 168 protected MatchingRule getMatchingRule() throws LdapException 169 { 170 if ( attributeType != null ) 171 { 172 MatchingRule mr = attributeType.getEquality(); 173 174 if ( mr == null ) 175 { 176 mr = attributeType.getOrdering(); 177 } 178 179 if ( mr == null ) 180 { 181 mr = attributeType.getSubstring(); 182 } 183 184 return mr; 185 } 186 else 187 { 188 return null; 189 } 190 } 191 192 193 /** 194 * Gets a normalizer using getMatchingRule() to resolve the matchingRule 195 * that the normalizer is extracted from. 196 * 197 * @return a normalizer associated with the attributeType or null if one cannot be found 198 * @throws LdapException if resolution of schema entities fail 199 */ 200 protected Normalizer getNormalizer() throws LdapException 201 { 202 if ( attributeType != null ) 203 { 204 MatchingRule mr = getMatchingRule(); 205 206 if ( mr == null ) 207 { 208 return null; 209 } 210 211 return mr.getNormalizer(); 212 } 213 else 214 { 215 return null; 216 } 217 } 218 219 220 /** 221 * Check if the value is stored into an instance of the given 222 * AttributeType, or one of its ascendant. 223 * 224 * For instance, if the Value is associated with a CommonName, 225 * checking for Name will match. 226 * 227 * @param attributeType The AttributeType we are looking at 228 * @return <code>true</code> if the value is associated with the given 229 * attributeType or one of its ascendant 230 */ 231 public boolean instanceOf( AttributeType attributeType ) throws LdapException 232 { 233 if ( ( attributeType != null ) && this.attributeType.equals( attributeType ) ) 234 { 235 if ( this.attributeType.equals( attributeType ) ) 236 { 237 return true; 238 } 239 240 return this.attributeType.isDescendantOf( attributeType ); 241 } 242 243 return false; 244 } 245 246 247 /** 248 * Gets the normalized (canonical) representation for the wrapped value. 249 * If the wrapped value is null, null is returned, otherwise the normalized 250 * form is returned. If the normalized Value is null, then the wrapped 251 * value is returned 252 * 253 * @return gets the normalized value 254 */ 255 public T getNormalizedValue() 256 { 257 if ( isNull() ) 258 { 259 return null; 260 } 261 262 if ( normalizedValue == null ) 263 { 264 return get(); 265 } 266 267 return getNormalizedValueCopy(); 268 } 269 270 271 /** 272 * Gets a reference to the the normalized (canonical) representation 273 * for the wrapped value. 274 * 275 * @return gets a reference to the normalized value 276 */ 277 public T getNormalizedValueReference() 278 { 279 if ( isNull() ) 280 { 281 return null; 282 } 283 284 if ( normalizedValue == null ) 285 { 286 return wrappedValue; 287 } 288 289 return normalizedValue; 290 291 } 292 293 294 /** 295 * Check if the contained value is null or not 296 * 297 * @return <code>true</code> if the inner value is null. 298 */ 299 public final boolean isNull() 300 { 301 return wrappedValue == null; 302 } 303 304 305 /** 306 * This method is only used for serialization/deserialization 307 * 308 * @return Tells if the wrapped value and the normalized value are the same 309 */ 310 /* no qualifier */ final boolean isSame() 311 { 312 return same; 313 } 314 315 316 /** 317 * Uses the syntaxChecker associated with the attributeType to check if the 318 * value is valid. Repeated calls to this method do not attempt to re-check 319 * the syntax of the wrapped value every time if the wrapped value does not 320 * change. Syntax checks only result on the first check, and when the wrapped 321 * value changes. 322 * 323 * @see Value#isValid() 324 */ 325 public final boolean isValid() 326 { 327 if ( valid != null ) 328 { 329 return valid; 330 } 331 332 if ( attributeType != null ) 333 { 334 valid = attributeType.getSyntax().getSyntaxChecker().isValidSyntax( get() ); 335 } 336 else 337 { 338 valid = false; 339 } 340 341 return valid; 342 } 343 344 345 /** 346 * Uses the syntaxChecker associated with the attributeType to check if the 347 * value is valid. Repeated calls to this method do not attempt to re-check 348 * the syntax of the wrapped value every time if the wrapped value does not 349 * change. Syntax checks only result on the first check, and when the wrapped 350 * value changes. 351 * 352 * @see ServerValue#isValid() 353 */ 354 public final boolean isValid( SyntaxChecker syntaxChecker ) throws LdapException 355 { 356 if ( syntaxChecker == null ) 357 { 358 String message = I18n.err( I18n.ERR_04139, toString() ); 359 LOG.error( message ); 360 throw new LdapException( message ); 361 } 362 363 valid = syntaxChecker.isValidSyntax( getReference() ); 364 365 return valid; 366 } 367 368 369 /** 370 * Normalize the value. In order to use this method, the Value 371 * must be schema aware. 372 * 373 * @exception LdapException If the value cannot be normalized 374 */ 375 public void normalize() throws LdapException 376 { 377 normalized = true; 378 normalizedValue = wrappedValue; 379 } 380 381 382 /** 383 * Tells if the value has already be normalized or not. 384 * 385 * @return <code>true</code> if the value has already been normalized. 386 */ 387 public final boolean isNormalized() 388 { 389 return normalized; 390 } 391 392 393 /** 394 * Set the normalized flag. 395 * 396 * @param the value : true or false 397 */ 398 public final void setNormalized( boolean normalized ) 399 { 400 this.normalized = normalized; 401 } 402 }