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 java.util.HashSet;
032    
033    import org.opends.server.admin.std.server.AttributeSyntaxCfg;
034    import org.opends.server.api.ApproximateMatchingRule;
035    import org.opends.server.api.AttributeSyntax;
036    import org.opends.server.api.EqualityMatchingRule;
037    import org.opends.server.api.OrderingMatchingRule;
038    import org.opends.server.api.SubstringMatchingRule;
039    import org.opends.server.config.ConfigException;
040    import org.opends.server.core.DirectoryServer;
041    import org.opends.server.types.ByteString;
042    
043    
044    
045    import static org.opends.server.loggers.ErrorLogger.*;
046    import static org.opends.messages.SchemaMessages.*;
047    import org.opends.messages.MessageBuilder;
048    import static org.opends.server.schema.SchemaConstants.*;
049    import static org.opends.server.util.StaticUtils.*;
050    
051    
052    
053    /**
054     * This class implements the facsimile telephone number attribute syntax, which
055     * contains a printable string (the number) followed by zero or more parameters.
056     * Those parameters should start with a dollar sign may be any of the following
057     * strings:
058     * <UL>
059     *   <LI>twoDimensional</LI>
060     *   <LI>fineResolution</LI>
061     *   <LI>unlimitedLength</LI>
062     *   <LI>b4Length</LI>
063     *   <LI>a3Width</LI>
064     *   <LI>b4Width</LI>
065     *   <LI>uncompressed</LI>
066     * </UL>
067     */
068    public class FaxNumberSyntax
069           extends AttributeSyntax<AttributeSyntaxCfg>
070    {
071      /**
072       * The set of allowed fax parameter values, formatted entirely in lowercase
073       * characters.
074       */
075      public static final HashSet<String> ALLOWED_FAX_PARAMETERS =
076           new HashSet<String>(7);
077    
078      static
079      {
080        ALLOWED_FAX_PARAMETERS.add("twodimensional");
081        ALLOWED_FAX_PARAMETERS.add("fineresolution");
082        ALLOWED_FAX_PARAMETERS.add("unlimitedlength");
083        ALLOWED_FAX_PARAMETERS.add("b4length");
084        ALLOWED_FAX_PARAMETERS.add("a3width");
085        ALLOWED_FAX_PARAMETERS.add("b4width");
086        ALLOWED_FAX_PARAMETERS.add("uncompressed");
087      }
088    
089    
090    
091      // The default equality matching rule for this syntax.
092      private EqualityMatchingRule defaultEqualityMatchingRule;
093    
094      // The default ordering matching rule for this syntax.
095      private OrderingMatchingRule defaultOrderingMatchingRule;
096    
097      // The default substring matching rule for this syntax.
098      private SubstringMatchingRule defaultSubstringMatchingRule;
099    
100    
101    
102      /**
103       * Creates a new instance of this syntax.  Note that the only thing that
104       * should be done here is to invoke the default constructor for the
105       * superclass.  All initialization should be performed in the
106       * <CODE>initializeSyntax</CODE> method.
107       */
108      public FaxNumberSyntax()
109      {
110        super();
111      }
112    
113    
114    
115      /**
116       * {@inheritDoc}
117       */
118      public void initializeSyntax(AttributeSyntaxCfg configuration)
119             throws ConfigException
120      {
121        defaultEqualityMatchingRule =
122             DirectoryServer.getEqualityMatchingRule(EMR_CASE_IGNORE_OID);
123        if (defaultEqualityMatchingRule == null)
124        {
125          logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
126              EMR_CASE_IGNORE_OID, SYNTAX_FAXNUMBER_NAME));
127        }
128    
129        defaultOrderingMatchingRule =
130             DirectoryServer.getOrderingMatchingRule(OMR_CASE_IGNORE_OID);
131        if (defaultOrderingMatchingRule == null)
132        {
133          logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
134              OMR_CASE_IGNORE_OID, SYNTAX_FAXNUMBER_NAME));
135        }
136    
137        defaultSubstringMatchingRule =
138             DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID);
139        if (defaultSubstringMatchingRule == null)
140        {
141          logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
142              SMR_CASE_IGNORE_OID, SYNTAX_FAXNUMBER_NAME));
143        }
144      }
145    
146    
147    
148      /**
149       * Retrieves the common name for this attribute syntax.
150       *
151       * @return  The common name for this attribute syntax.
152       */
153      public String getSyntaxName()
154      {
155        return SYNTAX_FAXNUMBER_NAME;
156      }
157    
158    
159    
160      /**
161       * Retrieves the OID for this attribute syntax.
162       *
163       * @return  The OID for this attribute syntax.
164       */
165      public String getOID()
166      {
167        return SYNTAX_FAXNUMBER_OID;
168      }
169    
170    
171    
172      /**
173       * Retrieves a description for this attribute syntax.
174       *
175       * @return  A description for this attribute syntax.
176       */
177      public String getDescription()
178      {
179        return SYNTAX_FAXNUMBER_DESCRIPTION;
180      }
181    
182    
183    
184      /**
185       * Retrieves the default equality matching rule that will be used for
186       * attributes with this syntax.
187       *
188       * @return  The default equality matching rule that will be used for
189       *          attributes with this syntax, or <CODE>null</CODE> if equality
190       *          matches will not be allowed for this type by default.
191       */
192      public EqualityMatchingRule getEqualityMatchingRule()
193      {
194        return defaultEqualityMatchingRule;
195      }
196    
197    
198    
199      /**
200       * Retrieves the default ordering matching rule that will be used for
201       * attributes with this syntax.
202       *
203       * @return  The default ordering matching rule that will be used for
204       *          attributes with this syntax, or <CODE>null</CODE> if ordering
205       *          matches will not be allowed for this type by default.
206       */
207      public OrderingMatchingRule getOrderingMatchingRule()
208      {
209        return defaultOrderingMatchingRule;
210      }
211    
212    
213    
214      /**
215       * Retrieves the default substring matching rule that will be used for
216       * attributes with this syntax.
217       *
218       * @return  The default substring matching rule that will be used for
219       *          attributes with this syntax, or <CODE>null</CODE> if substring
220       *          matches will not be allowed for this type by default.
221       */
222      public SubstringMatchingRule getSubstringMatchingRule()
223      {
224        return defaultSubstringMatchingRule;
225      }
226    
227    
228    
229      /**
230       * Retrieves the default approximate matching rule that will be used for
231       * attributes with this syntax.
232       *
233       * @return  The default approximate matching rule that will be used for
234       *          attributes with this syntax, or <CODE>null</CODE> if approximate
235       *          matches will not be allowed for this type by default.
236       */
237      public ApproximateMatchingRule getApproximateMatchingRule()
238      {
239        // There is no approximate matching rule by default.
240        return null;
241      }
242    
243    
244    
245      /**
246       * Indicates whether the provided value is acceptable for use in an attribute
247       * with this syntax.  If it is not, then the reason may be appended to the
248       * provided buffer.
249       *
250       * @param  value          The value for which to make the determination.
251       * @param  invalidReason  The buffer to which the invalid reason should be
252       *                        appended.
253       *
254       * @return  <CODE>true</CODE> if the provided value is acceptable for use with
255       *          this syntax, or <CODE>false</CODE> if not.
256       */
257      public boolean valueIsAcceptable(ByteString value,
258                                       MessageBuilder invalidReason)
259      {
260        // Get a lowercase string representation of the value and find its length.
261        String valueString = toLowerCase(value.stringValue());
262        int    valueLength = valueString.length();
263    
264    
265        // The value must contain at least one character.
266        if (valueLength == 0)
267        {
268    
269          invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY.get());
270          return false;
271        }
272    
273    
274        // The first character must be a printable string character.
275        char c = valueString.charAt(0);
276        if (! PrintableString.isPrintableCharacter(c))
277        {
278    
279          invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE.get(
280                  valueString, String.valueOf(c), 0));
281          return false;
282        }
283    
284    
285        // Continue reading until we find a dollar sign or the end of the string.
286        // Every intermediate character must be a printable string character.
287        int pos = 1;
288        for ( ; pos < valueLength; pos++)
289        {
290          c = valueString.charAt(pos);
291          if (c == '$')
292          {
293            pos++;
294            break;
295          }
296          else
297          {
298            if (! PrintableString.isPrintableCharacter(c))
299            {
300    
301              invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE.get(
302                      valueString, String.valueOf(c), pos));
303            }
304          }
305        }
306    
307        if (pos >= valueLength)
308        {
309          // We're at the end of the value, so it must be valid unless the last
310          // character was a dollar sign.
311          if (c == '$')
312          {
313    
314            invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR.get(
315                    valueString));
316            return false;
317          }
318          else
319          {
320            return true;
321          }
322        }
323    
324    
325        // Continue reading until we find the end of the string.  Each substring
326        // must be a valid fax parameter.
327        int paramStartPos = pos;
328        while (pos < valueLength)
329        {
330          c = valueString.charAt(pos++);
331          if (c == '$')
332          {
333            String paramStr = valueString.substring(paramStartPos, pos);
334            if (! ALLOWED_FAX_PARAMETERS.contains(paramStr))
335            {
336    
337              invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER.get(
338                      valueString, paramStr, paramStartPos, (pos-1)));
339              return false;
340            }
341    
342            paramStartPos = pos;
343          }
344        }
345    
346    
347        // We must be at the end of the value.  Read the last parameter and make
348        // sure it is valid.
349        String paramStr = valueString.substring(paramStartPos);
350        if (! ALLOWED_FAX_PARAMETERS.contains(paramStr))
351        {
352          invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER.get(
353                  valueString, paramStr, paramStartPos, (pos-1)));
354          return false;
355        }
356    
357    
358        // If we've gotten here, then the value must be valid.
359        return true;
360      }
361    }
362