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