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    
029    
030    
031    import org.opends.server.admin.std.server.AttributeSyntaxCfg;
032    import org.opends.server.api.ApproximateMatchingRule;
033    import org.opends.server.api.AttributeSyntax;
034    import org.opends.server.api.EqualityMatchingRule;
035    import org.opends.server.api.OrderingMatchingRule;
036    import org.opends.server.api.SubstringMatchingRule;
037    import org.opends.server.config.ConfigException;
038    import org.opends.server.core.DirectoryServer;
039    import org.opends.server.types.ByteString;
040    import org.opends.server.types.DN;
041    
042    
043    
044    import static org.opends.server.loggers.debug.DebugLogger.*;
045    import org.opends.server.loggers.debug.DebugTracer;
046    import static org.opends.server.loggers.ErrorLogger.*;
047    import org.opends.server.types.DebugLogLevel;
048    import static org.opends.messages.SchemaMessages.*;
049    import org.opends.messages.MessageBuilder;
050    import static org.opends.server.schema.SchemaConstants.*;
051    import static org.opends.server.util.StaticUtils.*;
052    
053    
054    /**
055     * This class implements the name and optional UID attribute syntax, which holds
056     * values consisting of a DN, optionally followed by an octothorpe (#) and a bit
057     * string value.
058     */
059    public class NameAndOptionalUIDSyntax
060           extends AttributeSyntax<AttributeSyntaxCfg>
061    {
062      /**
063       * The tracer object for the debug logger.
064       */
065      private static final DebugTracer TRACER = getTracer();
066    
067    
068    
069      // The default equality matching rule for this syntax.
070      private EqualityMatchingRule defaultEqualityMatchingRule;
071    
072      // The default substring matching rule for this syntax.
073      private SubstringMatchingRule defaultSubstringMatchingRule;
074    
075    
076    
077      /**
078       * Creates a new instance of this syntax.  Note that the only thing that
079       * should be done here is to invoke the default constructor for the
080       * superclass.  All initialization should be performed in the
081       * <CODE>initializeSyntax</CODE> method.
082       */
083      public NameAndOptionalUIDSyntax()
084      {
085        super();
086      }
087    
088    
089    
090      /**
091       * {@inheritDoc}
092       */
093      public void initializeSyntax(AttributeSyntaxCfg configuration)
094             throws ConfigException
095      {
096        defaultEqualityMatchingRule =
097             DirectoryServer.getEqualityMatchingRule(EMR_UNIQUE_MEMBER_OID);
098        if (defaultEqualityMatchingRule == null)
099        {
100          logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
101              EMR_UNIQUE_MEMBER_OID, SYNTAX_NAME_AND_OPTIONAL_UID_NAME));
102        }
103    
104        defaultSubstringMatchingRule =
105             DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID);
106        if (defaultSubstringMatchingRule == null)
107        {
108          logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
109              SMR_CASE_IGNORE_OID, SYNTAX_NAME_AND_OPTIONAL_UID_NAME));
110        }
111      }
112    
113    
114    
115      /**
116       * Retrieves the common name for this attribute syntax.
117       *
118       * @return  The common name for this attribute syntax.
119       */
120      public String getSyntaxName()
121      {
122        return SYNTAX_NAME_AND_OPTIONAL_UID_NAME;
123      }
124    
125    
126    
127      /**
128       * Retrieves the OID for this attribute syntax.
129       *
130       * @return  The OID for this attribute syntax.
131       */
132      public String getOID()
133      {
134        return SYNTAX_NAME_AND_OPTIONAL_UID_OID;
135      }
136    
137    
138    
139      /**
140       * Retrieves a description for this attribute syntax.
141       *
142       * @return  A description for this attribute syntax.
143       */
144      public String getDescription()
145      {
146        return SYNTAX_NAME_AND_OPTIONAL_UID_DESCRIPTION;
147      }
148    
149    
150    
151      /**
152       * Retrieves the default equality matching rule that will be used for
153       * attributes with this syntax.
154       *
155       * @return  The default equality matching rule that will be used for
156       *          attributes with this syntax, or <CODE>null</CODE> if equality
157       *          matches will not be allowed for this type by default.
158       */
159      public EqualityMatchingRule getEqualityMatchingRule()
160      {
161        return defaultEqualityMatchingRule;
162      }
163    
164    
165    
166      /**
167       * Retrieves the default ordering matching rule that will be used for
168       * attributes with this syntax.
169       *
170       * @return  The default ordering matching rule that will be used for
171       *          attributes with this syntax, or <CODE>null</CODE> if ordering
172       *          matches will not be allowed for this type by default.
173       */
174      public OrderingMatchingRule getOrderingMatchingRule()
175      {
176        // There is no ordering matching rule by default.
177        return null;
178      }
179    
180    
181    
182      /**
183       * Retrieves the default substring matching rule that will be used for
184       * attributes with this syntax.
185       *
186       * @return  The default substring matching rule that will be used for
187       *          attributes with this syntax, or <CODE>null</CODE> if substring
188       *          matches will not be allowed for this type by default.
189       */
190      public SubstringMatchingRule getSubstringMatchingRule()
191      {
192        return defaultSubstringMatchingRule;
193      }
194    
195    
196    
197      /**
198       * Retrieves the default approximate matching rule that will be used for
199       * attributes with this syntax.
200       *
201       * @return  The default approximate matching rule that will be used for
202       *          attributes with this syntax, or <CODE>null</CODE> if approximate
203       *          matches will not be allowed for this type by default.
204       */
205      public ApproximateMatchingRule getApproximateMatchingRule()
206      {
207        // There is no approximate matching rule by default.
208        return null;
209      }
210    
211    
212    
213      /**
214       * Indicates whether the provided value is acceptable for use in an attribute
215       * with this syntax.  If it is not, then the reason may be appended to the
216       * provided buffer.
217       *
218       * @param  value          The value for which to make the determination.
219       * @param  invalidReason  The buffer to which the invalid reason should be
220       *                        appended.
221       *
222       * @return  <CODE>true</CODE> if the provided value is acceptable for use with
223       *          this syntax, or <CODE>false</CODE> if not.
224       */
225      public boolean valueIsAcceptable(ByteString value,
226                                       MessageBuilder invalidReason)
227      {
228        String valueString = value.stringValue().trim();
229        int    valueLength = valueString.length();
230    
231    
232        // See if the value contains the "optional uid" portion.  If we think it
233        // does, then mark its location.
234        int dnEndPos = valueLength;
235        int sharpPos = -1;
236        if (valueString.endsWith("'B") || valueString.endsWith("'b"))
237        {
238          sharpPos = valueString.lastIndexOf("#'");
239          if (sharpPos > 0)
240          {
241            dnEndPos = sharpPos;
242          }
243        }
244    
245    
246        // Take the DN portion of the string and try to normalize it.
247        try
248        {
249          DN.decode(valueString.substring(0, dnEndPos));
250        }
251        catch (Exception e)
252        {
253          if (debugEnabled())
254          {
255            TRACER.debugCaught(DebugLogLevel.ERROR, e);
256          }
257    
258          // We couldn't normalize the DN for some reason.  The value cannot be
259          // acceptable.
260    
261          invalidReason.append(ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN.get(
262                  valueString, getExceptionMessage(e)));
263          return false;
264        }
265    
266    
267    
268        // If there is an "optional uid", then normalize it and make sure it only
269        // contains valid binary digits.
270        if (sharpPos > 0)
271        {
272          int     endPos = valueLength - 2;
273          for (int i=sharpPos+2; i < endPos; i++)
274          {
275            char c = valueString.charAt(i);
276            if (! ((c == '0') || (c == '1')))
277            {
278    
279              invalidReason.append(
280                      ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT.get(
281                              valueString, String.valueOf(c), i));
282              return false;
283            }
284          }
285        }
286    
287    
288        // If we've gotten here, then the value is acceptable.
289        return true;
290      }
291    }
292