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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.schema; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.List; 033 034 import org.opends.server.admin.server.ConfigurationChangeListener; 035 import org.opends.server.admin.std.server.DirectoryStringAttributeSyntaxCfg; 036 import org.opends.server.api.ApproximateMatchingRule; 037 import org.opends.server.api.AttributeSyntax; 038 import org.opends.server.api.AttributeValueDecoder; 039 import org.opends.server.api.EqualityMatchingRule; 040 import org.opends.server.api.OrderingMatchingRule; 041 import org.opends.server.api.SubstringMatchingRule; 042 import org.opends.server.config.ConfigException; 043 import org.opends.server.core.DirectoryServer; 044 import org.opends.server.types.AttributeValue; 045 import org.opends.server.types.ByteString; 046 import org.opends.server.types.ConfigChangeResult; 047 import org.opends.server.types.DirectoryException; 048 049 050 import org.opends.server.types.ResultCode; 051 052 import static org.opends.server.loggers.ErrorLogger.*; 053 import static org.opends.messages.SchemaMessages.*; 054 055 import org.opends.messages.MessageBuilder; 056 import static org.opends.server.schema.SchemaConstants.*; 057 058 059 /** 060 * This class defines the directory string attribute syntax, which is simply a 061 * set of UTF-8 characters. By default, they will be treated in a 062 * case-insensitive manner, and equality, ordering, substring, and approximate 063 * matching will be allowed. 064 */ 065 public class DirectoryStringSyntax 066 extends AttributeSyntax<DirectoryStringAttributeSyntaxCfg> 067 implements ConfigurationChangeListener<DirectoryStringAttributeSyntaxCfg> 068 { 069 // The default approximate matching rule for this syntax. 070 private ApproximateMatchingRule defaultApproximateMatchingRule; 071 072 // Indicates whether we will allow zero-length values. 073 private boolean allowZeroLengthValues; 074 075 // The reference to the configuration for this directory string syntax. 076 private DirectoryStringAttributeSyntaxCfg currentConfig; 077 078 // The default equality matching rule for this syntax. 079 private EqualityMatchingRule defaultEqualityMatchingRule; 080 081 // The default ordering matching rule for this syntax. 082 private OrderingMatchingRule defaultOrderingMatchingRule; 083 084 // The default substring matching rule for this syntax. 085 private SubstringMatchingRule defaultSubstringMatchingRule; 086 087 088 089 /** 090 * A {@link String} attribute value decoder for this syntax. 091 */ 092 public static final AttributeValueDecoder<String> DECODER = 093 new AttributeValueDecoder<String>() 094 { 095 /** 096 * {@inheritDoc} 097 */ 098 public String decode(AttributeValue value) throws DirectoryException 099 { 100 // Make sure that the value is valid. 101 value.getNormalizedValue(); 102 return value.getStringValue(); 103 } 104 }; 105 106 107 108 /** 109 * Creates a new instance of this syntax. Note that the only thing that 110 * should be done here is to invoke the default constructor for the 111 * superclass. All initialization should be performed in the 112 * <CODE>initializeSyntax</CODE> method. 113 */ 114 public DirectoryStringSyntax() 115 { 116 super(); 117 } 118 119 120 121 /** 122 * {@inheritDoc} 123 */ 124 public void initializeSyntax(DirectoryStringAttributeSyntaxCfg configuration) 125 throws ConfigException 126 { 127 defaultApproximateMatchingRule = 128 DirectoryServer.getApproximateMatchingRule(AMR_DOUBLE_METAPHONE_OID); 129 if (defaultApproximateMatchingRule == null) 130 { 131 logError(ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE.get( 132 AMR_DOUBLE_METAPHONE_OID, SYNTAX_DIRECTORY_STRING_NAME)); 133 } 134 135 defaultEqualityMatchingRule = 136 DirectoryServer.getEqualityMatchingRule(EMR_CASE_IGNORE_OID); 137 if (defaultEqualityMatchingRule == null) 138 { 139 logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get( 140 EMR_CASE_IGNORE_OID, SYNTAX_DIRECTORY_STRING_NAME)); 141 } 142 143 defaultOrderingMatchingRule = 144 DirectoryServer.getOrderingMatchingRule(OMR_CASE_IGNORE_OID); 145 if (defaultOrderingMatchingRule == null) 146 { 147 logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get( 148 OMR_CASE_IGNORE_OID, SYNTAX_DIRECTORY_STRING_NAME)); 149 } 150 151 defaultSubstringMatchingRule = 152 DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID); 153 if (defaultSubstringMatchingRule == null) 154 { 155 logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get( 156 SMR_CASE_IGNORE_OID, SYNTAX_DIRECTORY_STRING_NAME)); 157 } 158 159 160 // This syntax is one of the Directory Server's core syntaxes and therefore 161 // it may be instantiated at times without a configuration entry. If that 162 // is the case, then we'll exit now before doing anything that could require 163 // access to that entry. 164 if (configuration == null) 165 { 166 return; 167 } 168 169 currentConfig = configuration; 170 currentConfig.addDirectoryStringChangeListener(this); 171 allowZeroLengthValues = currentConfig.isAllowZeroLengthValues(); 172 } 173 174 175 176 /** 177 * Performs any finalization that may be necessary for this attribute syntax. 178 */ 179 public void finalizeSyntax() 180 { 181 currentConfig.removeDirectoryStringChangeListener(this); 182 } 183 184 185 186 /** 187 * Retrieves the common name for this attribute syntax. 188 * 189 * @return The common name for this attribute syntax. 190 */ 191 public String getSyntaxName() 192 { 193 return SYNTAX_DIRECTORY_STRING_NAME; 194 } 195 196 197 198 /** 199 * Retrieves the OID for this attribute syntax. 200 * 201 * @return The OID for this attribute syntax. 202 */ 203 public String getOID() 204 { 205 return SYNTAX_DIRECTORY_STRING_OID; 206 } 207 208 209 210 /** 211 * Retrieves a description for this attribute syntax. 212 * 213 * @return A description for this attribute syntax. 214 */ 215 public String getDescription() 216 { 217 return SYNTAX_DIRECTORY_STRING_DESCRIPTION; 218 } 219 220 221 222 /** 223 * Retrieves the default equality matching rule that will be used for 224 * attributes with this syntax. 225 * 226 * @return The default equality matching rule that will be used for 227 * attributes with this syntax, or <CODE>null</CODE> if equality 228 * matches will not be allowed for this type by default. 229 */ 230 public EqualityMatchingRule getEqualityMatchingRule() 231 { 232 return defaultEqualityMatchingRule; 233 } 234 235 236 237 /** 238 * Retrieves the default ordering matching rule that will be used for 239 * attributes with this syntax. 240 * 241 * @return The default ordering matching rule that will be used for 242 * attributes with this syntax, or <CODE>null</CODE> if ordering 243 * matches will not be allowed for this type by default. 244 */ 245 public OrderingMatchingRule getOrderingMatchingRule() 246 { 247 return defaultOrderingMatchingRule; 248 } 249 250 251 252 /** 253 * Retrieves the default substring matching rule that will be used for 254 * attributes with this syntax. 255 * 256 * @return The default substring matching rule that will be used for 257 * attributes with this syntax, or <CODE>null</CODE> if substring 258 * matches will not be allowed for this type by default. 259 */ 260 public SubstringMatchingRule getSubstringMatchingRule() 261 { 262 return defaultSubstringMatchingRule; 263 } 264 265 266 267 /** 268 * Retrieves the default approximate matching rule that will be used for 269 * attributes with this syntax. 270 * 271 * @return The default approximate matching rule that will be used for 272 * attributes with this syntax, or <CODE>null</CODE> if approximate 273 * matches will not be allowed for this type by default. 274 */ 275 public ApproximateMatchingRule getApproximateMatchingRule() 276 { 277 return defaultApproximateMatchingRule; 278 } 279 280 281 282 /** 283 * Indicates whether the provided value is acceptable for use in an attribute 284 * with this syntax. If it is not, then the reason may be appended to the 285 * provided buffer. 286 * 287 * @param value The value for which to make the determination. 288 * @param invalidReason The buffer to which the invalid reason should be 289 * appended. 290 * 291 * @return <CODE>true</CODE> if the provided value is acceptable for use with 292 * this syntax, or <CODE>false</CODE> if not. 293 */ 294 public boolean valueIsAcceptable(ByteString value, 295 MessageBuilder invalidReason) 296 { 297 if (allowZeroLengthValues || (value.value().length > 0)) 298 { 299 return true; 300 } 301 else 302 { 303 invalidReason.append( 304 ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE.get()); 305 return false; 306 } 307 } 308 309 310 311 /** 312 * Indicates whether zero-length values will be allowed. This is technically 313 * forbidden by the LDAP specification, but it was allowed in earlier versions 314 * of the server, and the discussion of the directory string syntax in RFC 315 * 2252 does not explicitly state that they are not allowed. 316 * 317 * @return <CODE>true</CODE> if zero-length values should be allowed for 318 * attributes with a directory string syntax, or <CODE>false</CODE> 319 * if not. 320 */ 321 public boolean allowZeroLengthValues() 322 { 323 return allowZeroLengthValues; 324 } 325 326 327 328 /** 329 * {@inheritDoc} 330 */ 331 public boolean isConfigurationChangeAcceptable( 332 DirectoryStringAttributeSyntaxCfg configuration, 333 List<Message> unacceptableReasons) 334 { 335 // The configuration will always be acceptable. 336 return true; 337 } 338 339 340 341 /** 342 * {@inheritDoc} 343 */ 344 public ConfigChangeResult applyConfigurationChange( 345 DirectoryStringAttributeSyntaxCfg configuration) 346 { 347 currentConfig = configuration; 348 allowZeroLengthValues = configuration.isAllowZeroLengthValues(); 349 350 return new ConfigChangeResult(ResultCode.SUCCESS, false); 351 } 352 } 353